Yii Framework action before every controller - php

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';
}
];

Related

Use a Zend function in every controllers

I need to be able to use a function (redirect with some parameters) from different controlers of my application.
I need to use $this->_helper->redirector($param1, $param2), and declare it just one time somewhere. Then I'll put this function in others controllers. If one day I modify the function, I don't need to modify it in each controller.
What I'm looking for is an equivalent of Symfony's services I guess.
Thanks for help :) .
What you 're asking for is called controller plugin in Laminas or Zend. You can code your own controller plugin, that you can use in every controller you want.
<?php
declare(strict_types=1);
namespace Application\Controller\Plugin;
use Laminas\Mvc\Controller\Plugin\AbstractPlugin;
class YourPlugin extends AbstractPlugin
{
public function __invoke($param1, $param2)
{
// your logic here
}
}
You have nothing more to do as to mention this plugin in your module.config.php file.
'controller_plugins' => [
'aliases' => [
'doSomething' => \Application\Controler\Plugin\YourPlugin::class,
],
'factories' => [
\Application\Controller\Plugin\YourPlugin::class => \Laminas\ServiceManager\Factory\InvokableFactory::class,
]
]
If you want to use some dependencies in your controller plugin, you can write your own factory for your plugin and add that dependencies via injection.
As your new plugin is mentioned in the application config, you can call your plugin in every controller you want.
<?php
declare(strict_types=1);
namespace Application\Controller;
class YourController extends AbstractActionController
{
public function indexAction()
{
$this->doSomething('bla', 'blubb');
}
}
Please do not use traits as a solution for your issue. Laminas / Zends already ships a redirect controller plugin. Perhaps a ready to use solution is already there or you can extend the redirect controller plugin ...

Yii2 extend console MessageController

I have some functionality, that I want to add to yii\console\controllers\MessageController::actionExtract().
So normally what I have done - extended yii controller with my own controller and placed it to app\commands directory.
<?php
namespace app\commands;
class MessageController extends \yii\console\controllers\MessageController{ /* .. */ }
For test purposes I added method named actionTest.
When I do > yii command, all I get is
Now I copy-pasted exactly same controller and just renamed it to MsgController. Previous controller left intact.
So now > yii gives me
yii message/test - 'Unknown command message/test'
yii msg/test - 'OK'
My app\config\console.php has 'controllerNamespace' => 'app\commands'
How should I properly extend MessageController and continue use standard yii command (means not changing controller name to have new command)?
Extend the controller like you did and in console configuration add:
'controllerMap' => [
'message' => 'app\commands\MessageController',
],

laravel 5 : Extend a Facade

I need to handle different types of DB depending on the client.
I created a Facade called MyDBFacade where I can call my own functions.
For example:
MyDBFacade::createDBUser("MyUser"); // will create a DB user whatever I'm using Postgres or SQL Server
Is there a possibility to extends the framework Facade DB:: in a way I could add my own functions and then call DB::createUser("MyUser") ?
Any clue or idea would be appreciate.
Thanks in advance, have a nice day.
Let's say that you define your custom facade in app/Facades/MyDBFacade.php
<?php
namespace App\Facades;
use Illuminate\Support\Facades\DB;
class MyDBFacade extends DB
{
// ...
}
You just need to change single line in config/app.php, from
'DB' => Illuminate\Support\Facades\DB::class,
to
'DB' => App\Facades\MyDBFacade::class,
And it all should work now.
You can create / extend your Facade like this:
<?php namespace YourNameSpace\Facades;
class MyDBFacade extends Illuminate\Support\Facades\DB {
/**
* Create your custom methods here...
*/
public static function anyMethod($active)
{
/// do what you have to do
}
}
And then replace (or add it as a new one) to your app/config/app.php:
'aliases' => array(
'MyDBFacade' => 'YourNameSpace\Facades\MyEventFacade::class',
),
Remember to execute composer dump-autoload at the end.
Hope this helps!

create shared view model in zend framework 2 project

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

Yii2 - How do I AutoLoad a custom class?

I have created the following custom class that I'd like to use in my Yii2 application:
#common/components/helper/CustomDateTime.php
namespace common\components\helper;
class CustomDateTime{function Now() {...}}
I want to use this class like this:
public function actionDelete($id)
{
$account = $this->findModel($id);
$account->archived = 1;
$account->archived_date = CustomDateTime::Now();
$account->save();
return $this->redirect(['index']);
}
In my #common/config/bootstrap.php file I've created a classMap according to this http://www.yiiframework.com/doc-2.0/guide-concept-autoloading.html.
Yii::$classMap['CustomDateTime'] = '#common/components/helper/CustomDateTime.php';
But I am getting the error: Class 'app\controllers\myapp\CustomDateTime' not found
QUESTION: How do I create a classMap so that I don't have to use the use statement at the beginning of every controller to access my custom class?
Yii 1.1 used to have an option in the config file to 'import' a set of code so that a class file could be autoloaded when it was called.
SOLUTION
Many thanks to #Animir for redirecting me back to the original documentation. http://www.yiiframework.com/doc-2.0/guide-concept-autoloading.html.
I found that I can use the following in my #common/config/bootstrap.php file
Yii::$classMap['CustomDateTime'] = '#common/components/helper/CustomDateTime.php';
BUT - it only works when the the CustomDateTime.php file does NOT have a declared namespace.
//namespace common\components\helper;
class CustomDateTime{function Now() {...}}
Just add use statement in file, where you use a class.
use common\components\helper\CustomDateTime;
/* some code */
public function actionDelete($id)
{
$dateNow = CustomDateTime::Now();
/* some code */
}
/* some code */
You can do this way too without the use of use
Yii::$app->cdt->Now(); // cdt - CustomDateTime
but for this thing to get accomplished successfully you add below to app/config/web.php (the config file)
...
'components' => [
'cdt' => [
'class' => 'common\components\helper\CustomDateTime',
],
...
]
...
Auto load in Yii 2 is pretty easy. You can use it by loading the class with config main file. like
You have created your class in components/helper/CustomDateTime.php . and now in your config/main.php in the top of the file add below code
require_once( dirname(__FILE__) . '/../components/helper/CustomDateTime.php');
Now your class is autoloaded in your project where ever you want to use it you can use like in your controller,model or view
Simply use like this
CustomDateTime-><methodName>();
Try this i have used this in my project.
For refrence you can use this link. click here
I know it's been long since this question was asked. I came across this and to share what I do.
I usually use an alias after use statement instead of adding 100 of lines of use statements for each model or class objects. Adding classMap for many of the classes that you use is not a good idea in my view. If you do that you'll be just adding unnecessary mapping even when you are not using those objects.
Here's what I do
use Yii;
use common\helpers as Helper;
use yii\helpers as YiiHelper;
use common\models as Model;
use common\components as Component;
And in the controller
public function actionIndex(){
$model = Model\SomeModel();
if(Yii::$app->request->isPost){
$post = Yii::$app->request->post('SomeModel');
$model->text = Helper\Text::clean($post['text']);
$model->text = YiiHelper\Html::encode($model->text);
if($model->save()){
return $this->render('thank_you');
}
}
}
Hope this helps :)

Categories