Yii2 в сторонних приложениях

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
arma
Сообщения: 9
Зарегистрирован: 2014.03.12, 22:09

Yii2 в сторонних приложениях

Сообщение arma »

Привет,

Yii2 работает в сторонних приложениях так:

Код: Выделить всё

echo Yii::$app->runAction('site/login');
 
где в контроллере вьюха рендерится через renderPartial.

Каким образом можно заставить Yii2 корректо работать с включенными CsrfValidation и CookieValidation в конфиге:

Код: Выделить всё

'components' => [
    'request' => [
        'enableCsrfValidation' => true,
        'enableCookieValidation' => true,
    ],
];
Последний раз редактировалось arma 2014.03.13, 15:58, всего редактировалось 1 раз.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Yii2 в сторонних приложениях и Csrf+Cookie Validation

Сообщение samdark »

Либо отключить, либо передавать токен.
arma
Сообщения: 9
Зарегистрирован: 2014.03.12, 22:09

Re: Yii2 в сторонних приложениях

Сообщение arma »

Спасибо за ответ.

Как можно заставить работать debug панель при вызове:

Код: Выделить всё

echo Yii::$app->runAction('site/login');
?
Как ее правильно подгрузить?

Понятно что костыль будет, но уж очень шикарная панель.
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Yii2 в сторонних приложениях

Сообщение samdark »

Без использования View никак.
arma
Сообщения: 9
Зарегистрирован: 2014.03.12, 22:09

Re: Yii2 в сторонних приложениях

Сообщение arma »

Думаю кому-то понадобится еще. Сделал так.

Расширил компонент Response, разделил выдачу хедеров и выдачу контента на 2 метода. Стандартный же Yii::$app->response->send() отдает все вместе: и хедеры и контент сразу, что не подходит.
За счет разделения, обработку запроса и выдачу хедеров можно будет включить в свое сторонее приложение в самом начале, а выдачу контента (renderPartial в экшнах) лишь в определенных нужных страницах, внутри уже имеющегося HTML.

/components/Myresponse.php:

Код: Выделить всё

<?php

namespace app\components;

use yii\web\Response;

/**
 * Class MyResponse
 * 
 * Divides Headers and Content Response
 */
class MyResponse extends Response
{
    /**
     * Send Headers to user
     */
    public function sendYiiHeaders()
    {
        if ($this->isSent) {
            return;
        }
        $this->trigger(self::EVENT_BEFORE_SEND);
        $this->prepare();
        $this->trigger(self::EVENT_AFTER_PREPARE);
        $this->sendHeaders();
    }

    /**
     * Send Content to user
     */
    public function sendYiiContent()
    {
        $this->sendContent();
        $this->trigger(self::EVENT_AFTER_SEND);
        $this->isSent = true;
    }
    
}
Конфиг
/config/web.php:

Код: Выделить всё

...
        'request' => [
            'enableCsrfValidation' => true,
            'enableCookieValidation' => true,
        ],
        'response' => [
            'class' => 'app\components\MyResponse',
        ],
...
Далее в своем стороннем приложении, где-то в самом начале подгружаем Yii, обрабатываем и отдаем хедеры.
include.php:

Код: Выделить всё

<?php
/**
 * @link https://github.com/yiisoft/yii2/blob/master/docs/guide/using-3rd-party-libraries.md#using-yii-in-3rd-party-systems
 */

// comment out the following two lines when deployed to production
defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');

require(__DIR__ . '/vendor/autoload.php');
require(__DIR__ . '/vendor/yiisoft/yii2/Yii.php');

$yiiConfig = require(__DIR__ . '/config/web.php');
new yii\web\Application($yiiConfig); // No 'run()' invocation!
require(__DIR__ . '/config/aliases.php');

/**
 * Handle User Request
 */
Yii::$app->trigger(Yii\web\application::EVENT_BEFORE_REQUEST);
Yii::$app->handleRequest(Yii::$app->getRequest());
Yii::$app->trigger(Yii\web\application::EVENT_AFTER_REQUEST);

/**
 * Send Headers
 */
Yii::$app->response->sendYiiHeaders();

И уже на определенных страницах где надо отдать HTML content:

Код: Выделить всё

Yii::$app->response->sendYiiContent();
Например страница /forgot-password.php старого приложения:

Код: Выделить всё

<?php
    $pageIndependent=true;
    include 'myheader.inc.php'; // где-то здесь происходит инициализация Yii и вызов Yii::$app->response->sendYiiHeaders();

    Yii::$app->response->sendYiiContent();

    include 'myfooter.inc.php';
Далее чтобы полноценно обрабатывать только нужные url-ы стороннего приложения c помощью Yii, прописал вручную правила:

Код: Выделить всё

...
    'components' => [
        'urlManager' => [
            'class' => 'yii\web\UrlManager',
            'showScriptName' => false,
            'enablePrettyUrl' => true,
            'enableStrictParsing' => true,
            'rules' => [
                'forgot-password' => 'site/forgot-password',
                '<controller:^(gii|debug).*>' => '<controller>', // don't block gii and debug
                
                '<controller:.*>' => 'oldsite/ignore', // fake controller for urls Yii don't own
            ],
        ],
    ]
...
 
Последнее правило - служит как заглушка для урлов старого сайта. Fake-контроллер с выключенным CsrfValidation, в котором не выводится ничего.
/controllers/OldsiteController.php:

Код: Выделить всё

<?php

namespace app\controllers;

use Yii;
use yii\web\controller;

/**
 * Class OldsiteController for Existing application
 *
 * @package app\controllers
 */
class OldsiteController extends Controller
{
    public $enableCsrfValidation = false;
    
    /**
     * Default cap action used for all old urls outside of Yii
     *
     * @return null
     */
    public function actionIgnore()
    {
        return null;
    }
}

С виду не такой уж и костыль, Yii очень крут что можно легко переопределить поведения каких-то Core компонентов.
Фактически фреймворк работает полноценно в уже существующем приложении.
В итоге и овцы сыты и волки целы.


Думаю можно сделать как-то легче для стороннего приложения и правильнее без fake-контроллера, поэтому замечания очень приветствуются.
Последний раз редактировалось arma 2014.04.03, 18:57, всего редактировалось 1 раз.
arma
Сообщения: 9
Зарегистрирован: 2014.03.12, 22:09

Re: Yii2 в сторонних приложениях

Сообщение arma »

Продолжаю тему.

Появилась необходимость в 3rd party приложении сделать так:

Код: Выделить всё

<?= Html::a('Manager Users', ['multiuser/manage']) ?>
те показывать правильно ссылки из Yii приложения. Вышеописанный код не работает, тк Yii::$app->controller null.

Те фактически необходимо за пределами view использовать Yii::$app->controller

Обнуляется Yii::$app->controller здесь:
https://github.com/yiisoft/yii2/blob/ma ... e.php#L435
Непонятно для чего сделано, тк изначально если Yii::$app->controller null то $oldController тоже будет null;
На очистку памяти не очень похоже.


Вопрос:
есть ли способ красиво переопределить метод runAction из Core yii\base\Module?

Было так:

Код: Выделить всё

    public function runAction($route, $params = [])
    {
        $parts = $this->createController($route);
        if (is_array($parts)) {
            /** @var Controller $controller */
            list($controller, $actionID) = $parts;
            $oldController = Yii::$app->controller;
            Yii::$app->controller = $controller;
            $result = $controller->runAction($actionID, $params);
            Yii::$app->controller = $oldController;

            return $result;
        } else {
            $id = $this->getUniqueId();
            throw new InvalidRouteException('Unable to resolve the request "' . ($id === '' ? $route : $id . '/' . $route) . '".');
        }
    }
 
Хочу сделать так:

Код: Выделить всё

    public function runAction($route, $params = [])
    {
        $parts = $this->createController($route);
        if (is_array($parts)) {
            /** @var Controller $controller */
            list($controller, $actionID) = $parts;
            $oldController = Yii::$app->controller;
            Yii::$app->controller = $controller;
            $result = $controller->runAction($actionID, $params);
            if ($oldController !== null) { // добавлено
                Yii::$app->controller = $oldController;
            } // добавлено

            return $result;
        } else {
            $id = $this->getUniqueId();
            throw new InvalidRouteException('Unable to resolve the request "' . ($id === '' ? $route : $id . '/' . $route) . '".');
        }
    }
 
Заранее спасибо тем кто откликнется.
Последний раз редактировалось arma 2014.04.02, 21:52, всего редактировалось 1 раз.
arma
Сообщения: 9
Зарегистрирован: 2014.03.12, 22:09

Re: Yii2 в сторонних приложениях

Сообщение arma »

lancedevnull,
да, я именно это и словил.

Поэтому начал искать и вышел на yii\base\Module где Yii::$app->controller обнуляется.
https://github.com/yiisoft/yii2/blob/ma ... e.php#L435
arma
Сообщения: 9
Зарегистрирован: 2014.03.12, 22:09

Re: Yii2 в сторонних приложениях

Сообщение arma »

Как решил:

Просто использовал вместо relative route, которому надо Active Controller:

Код: Выделить всё

<?= Html::a('Manager Users', ['multiuser/manage']) ?>
absolute route:

Код: Выделить всё

<?= Html::a('Manager Users', ['/multiuser/manage']) ?>
Ответить