Widgets и Themes в консольных командах

Обсуждение документации. Переводы Cookbook и авторские рецепты.
Ответить
Аватара пользователя
aser
Сообщения: 167
Зарегистрирован: 2009.04.02, 14:25
Откуда: Киев

Widgets и Themes в консольных командах

Сообщение aser »

Искал, не нашел решения.
Задача была такая: Есть консольные команды по отправке рассылки в которых формируются шаблон рассылки. Вот в шаблон рассылки понадобилось вставить widget с сайта. После вставки, рассылка с cron перестала уходить. Оказалось что консольные команды не умеют работать ни с Themes, ни с Widgets.

Решил переопределением классов CConsoleCommand и CConsoleApplication, расширив методами с CBaseController и CWebApplication

app.components.ConsoleApplication.php

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

class ConsoleApplication extends CConsoleApplication
{
    private $_theme;

    /**
     * Returns the widget factory.
     * @return IWidgetFactory the widget factory
     * @since 1.1
     */
    public function getWidgetFactory()
    {
        return Yii::app()->getComponent('widgetFactory');
    }

    /**
     * @return CThemeManager the theme manager.
     */
    public function getThemeManager()
    {
        return $this->getComponent('themeManager');
    }

    /**
     * @return CTheme the theme used currently. Null if no theme is being used.
     */
    public function getTheme()
    {
        if(is_string($this->_theme))
            $this->_theme=$this->getThemeManager()->getTheme($this->_theme);
        return $this->_theme;
    }

    /**
     * @param string $value the theme name
     */
    public function setTheme($value)
    {
        $this->_theme=$value;
    }

    /**
     * Returns the view renderer.
     * If this component is registered and enabled, the default
     * view rendering logic defined in {@link CBaseController} will
     * be replaced by this renderer.
     * @return IViewRenderer the view renderer.
     */
    public function getViewRenderer()
    {
        return $this->getComponent('viewRenderer');
    }
}
Учим консольные команды работать с виджетами
app.components.ConsoleCommand.php

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

class ConsoleCommand extends CConsoleCommand
{
    private $_widgetStack=array();

    /**
     * Creates a widget and initializes it.
     * This method first creates the specified widget instance.
     * It then configures the widget's properties with the given initial values.
     * At the end it calls {@link CWidget::init} to initialize the widget.
     * Starting from version 1.1, if a {@link CWidgetFactory widget factory} is enabled,
     * this method will use the factory to create the widget, instead.
     * @param string $className class name (can be in path alias format)
     * @param array $properties initial property values
     * @return CWidget the fully initialized widget instance.
     */
    public function createWidget($className,$properties=array())
    {
        $widget=Yii::app()->getWidgetFactory()->createWidget($this,$className,$properties);
        $widget->init();
        return $widget;
    }


    /**
     * Creates a widget and executes it.
     * @param string $className the widget class name or class in dot syntax (e.g. application.widgets.MyWidget)
     * @param array $properties list of initial property values for the widget (Property Name => Property Value)
     * @param boolean $captureOutput whether to capture the output of the widget. If true, the method will capture
     * and return the output generated by the widget. If false, the output will be directly sent for display
     * and the widget object will be returned. This parameter is available since version 1.1.2.
     * @return mixed the widget instance when $captureOutput is false, or the widget output when $captureOutput is true.
     */
    public function widget($className,$properties=array(),$captureOutput=false)
    {
        if($captureOutput)
        {
            ob_start();
            ob_implicit_flush(false);

            $widget=$this->createWidget($className,$properties);
            $widget->run();
            return ob_get_clean();
        }
        else
        {
            $widget=$this->createWidget($className,$properties);
            $widget->run();
            return $widget;
        }
    }

    /**
     * Creates a widget and executes it.
     * This method is similar to {@link widget()} except that it is expecting
     * a {@link endWidget()} call to end the execution.
     * @param string $className the widget class name or class in dot syntax (e.g. application.widgets.MyWidget)
     * @param array $properties list of initial property values for the widget (Property Name => Property Value)
     * @return CWidget the widget created to run
     * @see endWidget
     */
    public function beginWidget($className,$properties=array())
    {
        $widget=$this->createWidget($className,$properties);
        $this->_widgetStack[]=$widget;
        return $widget;
    }

    /**
     * Ends the execution of the named widget.
     * This method is used together with {@link beginWidget()}.
     * @param string $id optional tag identifying the method call for debugging purpose.
     * @return CWidget the widget just ended running
     * @throws CException if an extra endWidget call is made
     * @see beginWidget
     */
    public function endWidget($id='')
    {
        if(($widget=array_pop($this->_widgetStack))!==null)
        {
            $widget->run();
            return $widget;
        }
        else
            throw new CException(Yii::t('yii','{controller} has an extra endWidget({id}) call in its view.',
                array('{controller}'=>get_class($this),'{id}'=>$id)));
    }
}
 
Запускаем приложение от ConsoleApplication
cron.php

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

require_once('/srv/www/frameworks/yii.php');
require_once(dirname(__FILE__).'/protected/components/ConsoleApplication.php');
$configFile=dirname(__FILE__).'/protected/config/cron.php';
Yii::createApplication('ConsoleApplication',$configFile)->run();
В конфигурации подключаем недостающих компонентов
app.config.cron.php

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

'theme'=>'classic',
......
'components'=>array(
.....
        'widgetFactory'=>array(
            'class'=>'CWidgetFactory',
        ),
        'themeManager'=>array(
            'class'=>'CThemeManager',
        ),
......
),
Аватара пользователя
BuCeFaL
Сообщения: 447
Зарегистрирован: 2010.03.17, 21:22
Откуда: Kiev
Контактная информация:

Re: Widgets и Themes в консольных командах

Сообщение BuCeFaL »

Буквально только что наткнулся на те же грабли:

#0 /home/[...]/CBaseController.php(139): CComponent->__call('getWidgetFactor...', Array)
#1 /home/[...]/CBaseController.php(139): CConsoleApplication->getWidgetFactory()
#2 /home/[...]/CBaseController.php(182): CBaseController->createWidget('CContentDecorat...', Array)

Спасибо за решение.
Тоже рассылка сообщений и шаблон с использованием виджетов.
Аватара пользователя
BuCeFaL
Сообщения: 447
Зарегистрирован: 2010.03.17, 21:22
Откуда: Kiev
Контактная информация:

Re: Widgets и Themes в консольных командах

Сообщение BuCeFaL »

Только добавить еще в ConsoleApplication из CWebApplication:

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

//...
    private $_viewPath;

    /**
     * @return string the root directory of view files. Defaults to 'protected/views'.
     */
    public function getViewPath()
    {
        if($this->_viewPath!==null)
            return $this->_viewPath;
        else
            return $this->_viewPath=$this->getBasePath().DIRECTORY_SEPARATOR.'views';
    }
//...
 
jedi-m
Сообщения: 8
Зарегистрирован: 2012.06.06, 00:37
Откуда: Ульяновск

Re: Widgets и Themes в консольных командах

Сообщение jedi-m »

Спасибо за решение!
Как вариант, вместо переопределения ConsoleApplication, я создал behavior:

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

class ConsoleApplicationTemplater extends CBehavior {

    private $_theme;
    private $_viewPath;

    /**
     * Returns the widget factory.
     * @return IWidgetFactory the widget factory
     * @since 1.1
     */
    public function getWidgetFactory() {
        return $this->owner->getComponent('widgetFactory');
    }

    /**
     * @return CThemeManager the theme manager.
     */
    public function getThemeManager() {
        return $this->owner->getComponent('themeManager');
    }

    /**
     * @return CTheme the theme used currently. Null if no theme is being used.
     */
    public function getTheme() {
        if (is_string($this->_theme))
            $this->_theme = $this->getThemeManager()->getTheme($this->_theme);
        return $this->_theme;
    }

    /**
     * @param string $value the theme name
     */
    public function setTheme($value) {
        $this->_theme = $value;
    }

    /**
     * Returns the view renderer.
     * If this component is registered and enabled, the default
     * view rendering logic defined in {@link CBaseController} will
     * be replaced by this renderer.
     * @return IViewRenderer the view renderer.
     */
    public function getViewRenderer() {
        return $this->owner->getComponent('viewRenderer');
    }

    /**
     * @return string the root directory of view files. Defaults to 'protected/views'.
     */
    public function getViewPath() {
        if ($this->_viewPath !== null)
            return $this->_viewPath;
        else
            return $this->_viewPath = $this->owner->getBasePath() . DIRECTORY_SEPARATOR . 'views';
    }
}
 
и подключил его в конфиге console.php:

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

'behaviors'=>array(
    'templater'=>'ConsoleApplicationTemplater',
),
 
Ответить