Yii2 using AppAseets right way? - yii2

I have added the assets file(css, js) in assets/AppAssets.php
example:
public $css = [
'css/style.css',
'css/page-builder.css',
'css/settings.css',
'css/style-core.css',
'css/style-custom.css',
];
public $js = [
'js/jquery.min.js',
'js/jquery-migrate.min.js',
'js/jquery.themepunch.tools.min.js',
'js/jquery.themepunch.revolution.min.js',
'js/revolution.extension.slideanims.min.js',
'js/revolution.extension.layeranimation.min.js',
'js/revolution.extension.kenburn.min.js',
'js/revolution.extension.navigation.min.js',
'js/revolution.extension.parallax.min.js',
'js/revolution.extension.actions.min.js',
'js/revolution.extension.video.min.js',
'js/script.js',
'js/page-builder.js',
'js/effect.min.js',
'js/plugins.min.js',
];
public $jsOptions = ['position' => \yii\web\View::POS_HEAD];
public $depends = [
// 'yii\web\YiiAsset',
];
I have layouts like main, home, articles, gallery etc.
In the main layout I am using:
use app\assets\AppAsset;
AppAsset::register($this);
Now for home layout only, I need js/revolution*, but not for other layouts like article,
whereas for gallery layout I need to include some js files like mislider.js, I also want to maintain the order.
I tried to create a separate asset bundle for example assets/Home.php, which will only have revolution*.js files, but couldn't find a way, how I can the maintain the loading order as shown above.

Related

How to implement Filtering on YII restful GET api?

I am working on Restful APIs of Yii.
My controller name is ProductsController and the Model is Product.
When I call API like this GET /products, I got the listing of all the products.
But, now I want to filter the records inside the listing API.
For Example, I only want those records Which are having a product name as chairs.
How to implement this?
How to apply proper filtering on my Rest API. I am new to this. So, I have no idea how to implement this. I also followed their documentation but unable to understand.
May someone please suggest me a good example or a way to achieve this?
First of all you need to have validation rules in your model as usual.
Then it's the controllers job and depending on the chosen implementation I can give you some hints:
If your ProductsController extends yii\rest\ActiveController
Basically the easiest way because almost everything is already prepared for you. You just need to provide the $modelClass there and tweak actions() method a bit.
public function actions()
{
$actions = parent::actions();
$actions['index']['dataFilter'] = [
'class' => \yii\data\ActiveDataFilter::class,
'searchModel' => $this->modelClass,
];
return $actions;
}
Here we are modifying the configuration for IndexAction which is by default responsible for GET /products request handling. The configuration is defined here and we want to just add dataFilter key configured to use ActiveDataFilter which processes filter query on the searched model which is our Product. The other actions are remaining the same.
Now you can use DataProvider filters like this (assuming that property storing the product's name is name):
GET /products?filter[name]=chairs will return list of all Products where name is chairs,
GET /products?filter[name][like]=chairs will return list of all Products where name contains word chairs.
If your ProductsController doesn't extend yii\rest\ActiveController but you are still using DataProvider to get collection
Hopefully your ProductsController extends yii\rest\Controller because it will already benefit from serializer and other utilities but it's not required.
The solution is the same as above but now you have to add it by yourself so make sure your controller's action contains something like this:
$requestParams = \Yii::$app->getRequest()->getBodyParams(); // [1]
if (empty($requestParams)) {
$requestParams = \Yii::$app->getRequest()->getQueryParams(); // [2]
}
$dataFilter = new \yii\data\ActiveDataFilter([
'searchModel' => Product::class // [3]
]);
if ($dataFilter->load($requestParams)) {
$filter = $dataFilter->build(); // [4]
if ($filter === false) { // [5]
return $dataFilter;
}
}
$query = Product::find();
if (!empty($filter)) {
$query->andWhere($filter); // [6]
}
return new \yii\data\ActiveDataProvider([
'query' => $query,
'pagination' => [
'params' => $requestParams,
],
'sort' => [
'params' => $requestParams,
],
]); // [7]
What is going on here (numbers matching the code comments):
We are gathering request parameters from the body,
If these are empty we take them from the URL,
We are preparing ActiveDataFilter as mentioned above with searched model being the Product,
ActiveDataFilter object is built using the gathered parameters,
If the build process returns false it means there is an error (usually unsuccessful validation) so we return the object to user to see list of errors,
If the filter is not empty we are applying it to the database query for Product,
Finally we are configuring ActiveDataProvider object to return the filtered (and paginated and sorted if applicable) collection.
Now you can use DataProvider filters just as mentioned above.
If your ProductsController doesn't use DataProvider to get collection
You need to create your custom solution.

Several identical relations to one model in Yii2

I have a model File to store uploaded files and information about these files. Also there is a model with Company relations logo hasOne(File::className()) and photos hasMany(File::className()). Relations are written and works fine. Now I need to make an edit form for model Company in which I could edit files associated in logo and photos. Please tell me how I can do it.
Your relations can reflect the different use-cases, so in your Company model you can have
public function getLogo(){
//You'll need to add in the other attributes that define how Yii is to retrieve the logo from your images
return $this->hasOne(File::className(), ['companyId' => 'id', 'isLogo' => true]);
}
public function getPhotos(){
//You'll need to add in the other attributes that define how Yii is to retrieve the photos from your images
return $this->hasMany(File::className(), ['companyId' => 'id', 'isLogo' => false]);
}
You can then just use them like normal attributes;
$company = new Company;
$logo = $company->logo;
$photos = $company->photos;
You will then need to set up your controller to handle changes in these values to deal with uploads or new images, but that will depend on how you are handling the uploads.

How I can to turn off a theme in a especific yii2's view?

I am using yii2 with a bootstrap's theme, the theme is great but I need to turn off in one especific view of my controller. How I can do that?
You can change the theme at runtime by overriding the theme mapping. Adjust these for the routes you want to use, so if you are using a different theme, then point the pathMap and baseUrl to that theme, otherwise just point back to the original yii2 view files;
$this->getView()->theme = Yii::createObject([
'class' => '\yii\base\Theme',
'pathMap' => ['#app/views' => '#app/views'],
'baseUrl' => '#web/views',
]);
If you want change layout use in controller:
public $layout = 'YOUR_LAYOUT_NAME';
Or in special action:
public function actionView(){
$this->layout = 'YOUR_LAYOUT_NAME';
Read for $layout property http://www.yiiframework.com/doc-2.0/yii-base-controller.html#$layout-detail

Generate link in cakephp using Html helper

I am trying to simply create a link in my controller using the Html helper and I get the below error although I have added the necessary helper:
Call to a member function link() on a non-object
public $helpers = array('Html', 'Form');
$url = $this->Html->link(
'',
'http://www.example.com/',
['class' => 'button', 'target' => '_blank']
);
You can use Helpers inside your view files but not inside your controller
http://book.cakephp.org/2.0/en/views/helpers.html#using-helpers.
For example in your index.ctp
echo $this->Html->link(
__('My link'),
'http://www.example.com/',
array('class' => 'button', 'target' => '_blank')
);
Enabling Html Helper in your Controller is same as in your code.
class ExamplesController extends AppController {
$helpers = array('Html', 'Form');
public function index() {
//
}
}
This is a good question. I think your a little confused with MVC and the separation of concerns the design pattern provides. Take a look (again) at how CakePHP implements MVC: http://book.cakephp.org/2.0/en/cakephp-overview/understanding-model-view-controller.html.
The important thing to remember is that your controllers should never be concerned with creating anchor tags. That's the job of your views. Since helpers are a way to keep your views DRY (Don't Repeat Yourself) having one thats sole responsibility is to create HTML elements is really handy. Views are dependent on controllers to determine what variables are set, what their value is, as well as what helpers are loaded. For more information on Helpers as well as components for controllers and behaviors for models check out http://book.cakephp.org/2.0/en/getting-started/cakephp-structure.html as well as each of their individual documentation pages:
Helpers - http://book.cakephp.org/2.0/en/views/helpers.html
Components - http://book.cakephp.org/2.0/en/controllers/components.html,
Behaviors - http://book.cakephp.org/2.0/en/models/behaviors.html.
Now that you have a better understanding of MVC, let's take a look at your specific issue. Your wanting to create a link in your controller. I assume it might be dynamic depending on some other variables so I'm going to roll with that.
A common problem that you can solve you want to show a login/logout link depending on if the user is already logged in.
In app/Controller/ExampleController.php
class ExampleController extends AppController {
public $components = array('Auth');
public $helpers = array('Html', 'Form');
public function beforeRender() {
parent::beforeRender();
//if Auth::user() returns `null` the user is not logged in.
if ($this->Auth->user() != null) {
$logInOutText = 'Log out';
$logInOutUrl = array('controller' => 'users', 'action' => 'login');
} else {
$logInOutText = 'Log in';
$logInOutUrl = array('controller' => 'users', 'action' => 'logout');
}
$this->set(compact('logInOutText', 'logInOutUrl'));
}
}
You can then so something simple in your view. In this case I'm choosing the default layout because I want the links in every rendered page. app/View/Layouts/default.ctp
<!-- More HTML above -->
<?php
// "Html" in `$this->Html` refers to our HtmlHelper. Note that in a view file
// like a `.ctp`, `$this` referes to the View object, while above in the
// controller `$this` refers to the Controller object. In the case
// `$this->Html`, "Html" would refer to a component. The same goes for Models
// and behaviors.
echo $this->Html->link($logInOutText, $logInOutUrl); // Easy!
?>
<!-- More HTML below -->
I hope this helps. I know it's a lot to put together at one time.
Though it is not good practice. However still if you need this you can use following code in your controller
App::uses('HtmlHelper', 'View/Helper');
$yourTmpHtmlHelper = new HtmlHelper(new View());
$url=$yourTmpHtmlHelper->link(
'',
'http://www.example.com/',
['class' => 'button', 'target' => '_blank']
);
This should work for cakephp 2.*
Thanks

zend framework 2, return the rendered contents of a view inside a JSON Model

I am trying to create a JsonModel with an item in the variables 'html' containing the current rendered view. I would like to add this code to an event:
rather than this method: How to render ZF2 view within JSON response? which is in the controller, I would like to automate the process by moving it to an Event
I have the strategy in my module.config.php:
'strategies' => array(
'ViewJsonStrategy',
)
I have set up a setEventManager in the controller:
$events->attach(MvcEvent::EVENT_RENDER, function ($e) use ($controller) {
$controller->setRenderFormat($e);
}, -20);
Is this the best event to attach it to? would the RENDER_EVENT be better?
Now I would like to change the render of the page based on !$this->getRequest()->isXmlHttpRequest(), (commented out for debug)
public function setRenderFormat($e)
{
//if(!$this->getRequest()->isXmlHttpRequest())
//{
$controller = $e->getTarget();
$controllerClass = get_class($controller);
//Get routing info
$controllerArr = explode('\\', $controllerClass);
$currentRoute = array(
'module' => strtolower($controllerArr[0]),
'controller' => strtolower(str_replace("Controller", "", $controllerArr[2])),
'action' => strtolower($controller->getEvent()->getRouteMatch()->getParam('action'))
);
$view_template = implode('/',$currentRoute);
$viewmodel = new \Zend\View\Model\ViewModel();
$viewmodel->setTemplate($view_template);
$htmlOutput = $this->getServiceLocator()->get('viewrenderer')->render($viewmodel, $viewmodel);
$jsonModel = new JsonModel();
$jsonModel->setVariables(array(
'html' => $htmlOutput,
'jsonVar1' => 'jsonVal2',
'jsonArray' => array(1,2,3,4,5,6)
));
return $jsonModel;
//}
}
Strangely, (or not) this code works and produces the $jsonModel, however is doesn't overwite the normal HTML view with the json, but the same code (without the event) in a controller method, overwrites perfectly.
p.s Is there a better method to do the whole concept?
p.p.s how can I obtain the current View Template from within the controller, without resorting to 8 lines of code?
Thanks in advance!
Aborgrove
you are returning the view model from an event I thinks this doesn't have any effect in current viewmanager view model, fetch the current viewmodel from viewmanager and call setTerminal(true). or replace the created jsonmodel using the viewmanager