Исполнение виджета напрямую из адресной строки в Yii

В процессе работы AJAX приложений, возникает необходимость обновлять отдельные части документа без перезагрузки всей страницы. В базовом MVC варианте, для обновления каждого такого контейнера нужно создавать персональный скрипт (контроллер + отображение). Чтобы не дублировать отображения, вывод динамического блока будет правильно сделать виджетом. Этот виджет можно вызывать из как из базового отображения, как при первоначальном формировании страницы, так и при обновлении её отдельной части.

Во многих случаях может оказаться что контроллер и отображение, отвечающие за обновление части страницы, не содержат бизнес-логики, а являются простой оберткой к виджету. Чтобы не плодить не несущий смысловой нагрузки код, в некоторых случаях будет оптимально запускать виджет напрямую. Я не пробовал найти каких-то решений чтобы запустить виджет без контроллера, т.к. впоследствии вызов такого виджета будет тяжело переопределить, поэтому запускать виджет предлагаю как action уже существующего контроллера.

Пример контроллера Yii, который вызывет виджет как action:

class PageController extends CController
{

    public function actions()
    {
        return array(
            'widget' => array(
                'class' => 'PageWidget'
            )
        );
    }

    public function actionIndex()
    {
        Yii::app()->clientScript->registerCoreScript('jquery');

        $this->render('index');
    }

}

Так, мы пробуем из контроллера запустить виджет вместо экшена. Чтобы это было возможным, требуется чтобы в виджете был определен метод runWithParams(), который выполняет метод run() виджета:

class PageWidget extends CWidget
{

    public function runWithParams($params)
    {
        $this->run();
    }

}

Этого достаточно, чтобы запустить виджет вместо экшена контроллера в Yii. Для полноты картины, приведу еще отображение страницы, в нем виджет выводится в контейнере:

<div class="pageWidget">

   < ? $this->widget('PageWidget'); ? >

</div>

Код отображения виджета, в этом случае, должен быть примерно следующий:

<a href="< ? = Yii::app()->urlManager->createUrl('/page/widget'); ? >" onClick="
    $.ajax(
    {
        url: $(this).attr('href'),
        success: function (data)
        {
            $('#pageWidget').html(data);
        }
    });

    return false;
">AJAX Update</a>

Для решения задачи оказалось достаточно создать метод runWithParams, но более правильно, было бы также реализовать в классе интерфейс IAction.

UPD: Как показала практика, в реальных проектах лучше избегать подобных доработок. Лучше каждый виджет комплектовать контроллером или экшеном.

23.11.2012