Как вызвать экшен из другого контроллера в yii2.
  • 1699

Как вызвать экшен из другого контроллера/экшена в yii2.

Автор: admin | 24 июля (Вт.) 2018г. в 22ч.56м.

Зачем это нужно.

Бывают моменты в разработке на yii2, что нужно в одном экшене надо обратиться и вернуть результат от другого экшена, а дублировать код не хочется.

Для того, чтобы вызвать action какого-либо контроллера в view файле нужно перейти по ссылке или отправить форму. Также можно использовать перенаправление (редирект) и наконец, можно напрямую вызвать action метод контроллера внутри самого контроллера или создать объект и работать с его экшеном. В данном случае интересен именно последний вариант.   

Реализация вызова другого контроллера/экшена. 

Для того, чтобы вызвать в одном контроллере из экшена другой экшен нужно просто обратьиться к нужному методу, ведь экшкн - это просто метод класса. Для обращения к другому экшену, который находится в другом контроллере нужно действовать иначе. Как работает роутинг известно, например по нажатию на ссылку url разбирается на компоненты из которых извлекается информация об контроллере, экшене и параметрах. Поэтому обращаться к другому action методу будем с помощью привычных методов для формирования урлов Url::toRoute() или Url::to()

У нас есть метод action контроллера из которого мы обращаемся к другому экшену другого контроллера:
//Первый контроллер
class ProfileController extends Controller
{

    public function actionBlog($articleId)
    {
        $article = Articles::findOne($articleId);

        $userId = $article->createdBy;
        $profile = '';//вот тут мы получим результат с ProfileController actionProfile($userId)


        return $this->render('article', compact('article', 'profile'));
        
    }

//Второй целевой контроллер
class ProfileController extends Controller
{

    public function actionIndex($userId)
    {
        $profile = Profiles::findOne($userId);
        
        return $this->renderPartial('article',compact('profile'));
        
    }
Создадим вспомогательный метод в этом контроллере, для того, чтобы вынести в него логику вызова другого экшена.
public function makeAction($url)
    {
        $request = Yii::$app->request;
        $request->setUrl($url);
        list($route, $params) = $request->resolve();

        //создаем экземпляр контроллера
        $ca = Yii::$app->createController($route);
        if ($ca !== false) {
            /* @var $controller \yii\base\Controller */
            list($controller, $actionID) = $ca;
            $action = $controller->createAction($actionID);
            if ($action !== null) {
                //вызываем экшен
                return $action->runWithParams($params);
            }
        }
        return false;
    }​
Теперь обратимся к этому методу из actionBlog
public function actionBlog($articleId)
    {
        $article = Articles::findOne($articleId);

        $userId = $article->createdBy;

        $url = Url::toRoute(['profile/index', 'userId' => $userId]);
        $profile = $this->makeAction($url);//вот тут мы получим результат с ProfileController actionProfile($userId)


        return $this->render('article', compact('article', 'profile'));
        
    }​

Теперь в переменной $profile результат рендеринга из экшена, который был частью другого контроллера. Таким образом мы решили поставленную задачу и избежали дублирования кода.


 

Приветствую!

Меня зовут Сергей. Я - автор этого блога.

Если Вам был полезен материал на моем сайте, поддержите пожалуйста мой проект, чтобы о нем узнали другие люди - кликните plizz :) на иконку в соц. сети, чтобы поделиться материалом с другими.