create shared view model in zend framework 2 project - php

I want to assign generic variables to the view renderer outside the controller action.
I'd prefer to handle this in the module class bootstrap.
My question is, how do I create a view model in the module class bootstrap that can be shared with the controller .
My end result is to have the ability to add variables to the view model before we create a new instance of one inside the controller action.
Here's something I started on, however i cannot add variables to the declared viewmodel and have it persist to the controller's new instance of a view model.
Is there a way to create a view model and have it set as the renderer before dispatch.
Here's something i started but if i can get it in the module class bootstrap instead id prefer that.
I dont think this works though.
class BaseController extends AbstractActionController
{
protected $viewModel;
public function onDispatch(MvcEvent $e)
{
$this->viewModel = new ViewModel([
'module' => 'modulename',
'controller' => 'controllername',
'action' => 'actionname'
]);
parent::onDispatch($e);
}
}

In the Module.php you have access to the event object.
In this event you can set some variables like this :
$event->getViewModel()->setVariable('isAdmin', $isAdmin);
$event->getViewModel()->setVariable('var', $var);
$event->getViewModel()->setVariable('form', $form);
$event->getViewModel()->setVariable('uri', $uri[0]);
If you want to test more you can also do :
$widgetTemplate = new ViewModel();
$widgetTemplate = $widgetTemplate->setTemplate('widget/container');
$event->getViewModel()->addChild($widgetTemplate, 'widget');
Those variables are available in your layout.phtml. I didn't test if it's the same viewModel available in your controller, give me a feedback if you test this solution.
For a variable defined in module.php, you can also use the Zend\Container\Session component to modify it in controllers

Related

Yii Framework action before every controller

is there any "main" controller which fires before every other controller from folder "controllers"? I have a project where every user has his different site language, so I want to check the setting first and then set the language using:
Yii::$app->language='en-EN';
Right now I do this in every controller I have, but I guess it should be an easier option.
I had same problem while ago, and found a solution by adding another component.
How to load class at every page load in advanced app
Add class in config to components part and load it at start by adding to bootstrap.
config.php
$config = [
// ..
'components' => [
'InitRoutines' => [
'class' => 'app\commands\InitRoutines', // my custom class
],
],
];
$config['bootstrap'][] = 'InitRoutines';
Then make your class to extend Component with init() method
InitRoutines.php
namespace app\commands;
use Yii;
use yii\base\Component;
use app\commands\AppHelper;
use app\commands\Access;
class InitRoutines extends Component
{
// this method runs at start at every page load
public function init()
{
parent::init();
Access::checkForMaintenance(); // my custom method
Yii::$app->language = AppHelper::getUserLanguageCode(); // my custom method
}
}
You can attach to the application event beforeAction or beforeRequest and do your stuff here. It seems easier to me e.g.:
$config = [
// ..
'on beforeRequest' => function($event) {
Yii::$app->language='en-EN';
}
];

Laravel setting from database and accessible to all the Controllers and Views

Hi I am trying to load the Setting and Accessible to all the Controllers and views. Is there a nice way to do this.
As I mentioned, you can modify the controller that all other controllers extend from, and add the variables to the __construct() function. For instance in my 5.3 project, all controllers extend App\Http\Controllers\Controller. In that controller, add (or update, if the function exists) something like this:
protected $settings; // Protected so child controllers can't modify it
public function __construct() {
$this->settings = Settings::first();
}
You can do all sorts of logic here and set up any variables you want. Then in the child controllers, all you have to do to access them is use $this->settings, like
if($this->settings->my_setting == TRUE)
If you want to use it in a view, you'll have to pass it into the view. If you want to share it will all views, you can follow the instructions here.

zend framework 2: how to properly inject factory to controller to get different mapper classes?

I'm using Apigility, built on ZF2. Once request is dispatched to the controller's action, I need to choose proper adapter to hanle request - based on incomming parameters.
Normally, Controller is instantiated by ControllerFactory, where you can provide all dependencies, let say I need som kind of mapper class to be injected. It's easy, if I know, which one I will use in within the controller. It's problematic if I need to let controller decide which mapper to use.
Let's say user is requesting something like getStatus with param 'adapter1' and another user is accessing same action, but with param 'adapter2'.
So, I need to inject adapter1 mapper OR adapter2 mapper, which has similar interface, but different constructor.
What's the proper way how to handle this situation ?
On possible solution is to supply some kind of factory method, which will provide requested adapter, but - using the SM int the model class should be avoided.
Another way is to use SM directly in within Controller's action, but this in not best approach, because I can't reuse 'switch-case' logic for another actions / controllers.
How to handle this, please ?
You could use controller plugins for this.
Like that you can get the adapter inside your controller when you need it without injecting a ServiceManager and without adding all the logic to the factory. The adapter will only be instantiated when you request it in your controller action method.
First you need to create your controller plugin class (extending Zend\Mvc\Controller\Plugin\AbstractPlugin):
<?php
namespace Application\Controller\Plugin;
use Zend\Mvc\Controller\Plugin\AbstractPlugin;
class AdapterPlugin extends AbstractPlugin{
protected $adapterProviderService;
public function __constuct(AdapterProviderService $adapterProviderService){
$this->adapterProviderService = $adapterProviderService;
}
public function getAdapter($param){
// get the adapter using the param passed from controller
}
}
Then a factory to inject your service in the class:
<?php
namespace Application\Controller\Plugin\Factory;
use Application\Controller\Plugin\AdapterPlugin;
class AdapterPluginFactory implements FactoryInterface
{
/**
* #param ServiceLocatorInterface $serviceController
* #return AdapterPlugin
*/
public function createService(ServiceLocatorInterface $serviceController)
{
$serviceManager = $serviceController->getServiceLocator();
$adapterProvicerService = $serviceManager>get('Application\Service\AdapterProviderService');
return new AdapterPlugin($adapterProviderService);
}
}
Then you need to register your plugin in your module.config.php:
<?php
return array(
//...
'controller_plugins' => array(
'factories' => array(
'AdapterPlugin' => 'Application\Controller\Plugin\Factory\AdapterPluginFactory',
)
),
// ...
);
Now you can use it inside your controller action like this:
protected function controllerAction(){
$plugin = $this->plugin('AdapterPlugin');
// Get the param for getting the correct adapter
$param = $this->getParamForAdapter();
// now you can get the adapter using the plugin
$plugin->getAdapter($param);
}
Read more on controller plugins here in the documentation

Make things available in any view file Laravel

I have a question about making some elements available in any view file
Lets say im building a webshop and on every page i will be having my sidebar, shoppingcart, user greeting in the top.
How can i make these things available in all my view files?
I could make a class, lets say class Frontend
I could do something like this:
class Frontend {
static $me;
public function get(){
if(!self::$me){
self::$me = new self();
}
return self::$me;
}
private function getShoppingCart(){
// do things
}
public function getData(){
return array(
'Username' => User::find(1)->UserName,
'Cart' => $this->getShoppingCart()
);
}
}
Now in my controller i could pass this Frontend object into the view
View::make('file.view')->with(array('data' => Frontend::get()->getData()));
But this way i will end up with a god class containing way too much stuff and in every controller method i would have to pass these data, which is not relevant to the controller method
Is there a way in Laravel that makes specific data available across all view files?
Thanks!
Use share:
View::share('name', 'Steve');
as per http://laravel.com/docs/responses#views
To keep everything clean, every part of the page should be its own *.blade.php file which would be put together using a master template of sorts.
master.blade.php
#yield('includes.sidebar')
#yield('users.greeting')
#yield('store.shoppingcart')
Then you can use view composers so that each time these views are loaded, the data you want is injected into them. I would probably either create a new file which would get autoloaded, or if you have service providers for the separate portions of your app that these views would use, it would also go great in there.
View::composer('users.greeting', function($view)
{
$view->with('user', Auth::user());
});
In this case, it would make the user model available inside your view. This makes it very easy to manage which data gets injected into your views.
You are close with your 'god class' idea.
Setting a $data variable in a basecontroller has helped me with similar issues
class BaseController extends Controller {
protected $data;
public function __construct() {
$this->data['Username'] = User::find(1)->UserName
$this->data['Cart'] = $this->getShoppingCart()
}
}
class Frontend extends BaseController {
function someMethod(){
View::make('file.view', $this->data)
}
}

Controller within another Controller

Is it possible to instantiate a Controller class within another controller class using the Yii Framework
For example I have controller Student and and method actionShow of class student I have the following
public function actionShow()
{
$student = $this->loadStudent();
$studentContact = new Student_ContactController;
//Checking if there was an ajax request
if(Yii::app()->request->isAjaxRequest){
$this->renderPartial('show',array(
'student'=>$student,
));
}else{
$this->render('show',array(
'student'=>$student,
));
}
}
Is it possible to include this action in the method $studentContact = new Student_ContactController;
Getting errors, :-(
I do not know the Yii framework, but as it is an MVC framework, then getting data should be part of the model, therefore $studentContact should be an instance of a model, not of a controller.
If you really want to instanciate an instance of a controller then call the constructor with brackets:
$studentContact = new Student_ContactController();

Categories