Оглавление

Начало Основы Работа с формами Работа с БД Кэширование Расширение Yii Тестирование Специальные темы
Зачем реклама?

Создание расширений

Поскольку создание расширений подразумевает их использование сторонними разработчиками, процесс создания требует дополнительных усилий. Ниже приведены основные правила, которые необходимо соблюдать при создании расширений:

  • расширение должно быть самодостаточным, т.е. зависимость от внешних ресурсов должна быть минимальна. Очень неудобно, когда для работы расширения требуется устанавливать дополнительные пакеты, классы и иные файлы ресурсов;
  • все файлы расширения должны быть собраны в одной директории, имя которой должно совпадать с названием расширения;
  • классы расширения должны начинаться с префикса, чтобы избежать конфликтов имён с классами других расширений;
  • расширение должно включать подробную документацию по его установке и API, чтобы сократить время, затрачиваемое другими разработчиками на его подключение и изучение;
  • расширение должно использовать надлежащую лицензию. Если вы хотите, чтобы ваше расширение могло быть использовано как открытыми, так и закрытыми проектами, вы можете воспользоваться лицензиями BSD, MIT и др., но не GPL, т.к. последняя требует, чтобы код, в котором используется ваше расширение, также был открыт.

Ниже мы расскажем о том, как создать новое расширение в соответствии с классификацией, приведённой в обзоре. Пояснения в равной степени распространяются и на расширения, используемые исключительно в собственных проектах.

Компонент приложения #

Компонент приложения должен реализовывать интерфейс IApplicationComponent или расширять класс CApplicationComponent. Основной метод, который необходимо реализовать, — IApplicationComponent::init. В этом методе происходит инициализация компонента. Метод вызывается после того, как компонент создан и установлены начальные значения, указанные в конфигурации приложения.

По умолчанию компонент приложения создаётся и инициализируется только в момент первого обращения к нему в ходе обработки запроса. Если необходимо принудительно создавать компонент сразу после создания экземпляра приложения, то нужно добавить идентификатор этого компонента в свойство CApplication::preload.

Поведение #

Для того чтобы создать поведение, необходимо реализовать интерфейс IBehavior. Для удобства в Yii имеется класс CBehavior, реализующий этот интерфейс и предоставляющий некоторые общие методы. Наследуемые классы могут реализовать дополнительные методы, которые будут доступны в компонентах, к которым прикреплено поведение.

При разработке поведений для CModel и CActiveRecord можно наследовать классы CModelBehavior и CActiveRecordBehavior соответственно. Эти базовые классы предоставляют дополнительные возможности, специально созданные для CModel и CActiveRecord. К примеру, класс CActiveRecordBehavior реализует набор методов для обработки событий жизненного цикла ActiveRecord. Наследуемый класс, таким образом, может перекрыть эти методы и выполнить код, участвующий в жизненном цикле AR.

Следующий код демонстрирует пример поведения ActiveRecord. Если это поведение прикреплено к объекту AR и вызван метод save(), атрибутам create_time и update_time будет автоматически присвоено текущее время.

class TimestampBehavior extends CActiveRecordBehavior
{
    public function 
beforeSave($event)
    {
        if(
$this->owner->isNewRecord)
            
$this->owner->create_time=time();
        else
            
$this->owner->update_time=time();
    }
}

Виджет #

Виджет должен расширять класс CWidget или производные от него.

Наиболее простой способ создать виджет — расширить существующий виджет и переопределить его методы или заменить значения по умолчанию. Например, если вы хотите заменить CSS стиль для CTabView, то, используя виджет, нужно установить свойство CTabView::cssFile. Можно также расширить класс CTabView, чтобы при использовании виджета не требовалась постоянная конфигурация, следующим образом:

class MyTabView extends CTabView
{
    public function 
init()
    {
        if(
$this->cssFile===null)
        {
            
$file=dirname(__FILE__).DIRECTORY_SEPARATOR.'tabview.css';
            
$this->cssFile=Yii::app()->getAssetManager()->publish($file);
        }
        
parent::init();
    }
}

Выше мы переопределяем метод CWidget::init и, если свойство CTabView::cssFile не установлено, присваиваем ему значение URL нового CSS стиля по умолчанию. Файл нового CSS стиля необходимо поместить в одну папку с файлом класса MyTabView, чтобы их можно было упаковать как расширение. Поскольку CSS стиль не доступен из веб, его необходимо опубликовать как ресурс.

Чтобы написать виджет с нуля, нужно, как правило, реализовать два метода: CWidget::init и CWidget::run. Первый метод вызывается, когда мы используем конструкцию $this->beginWidget для вставки виджета в представление, а второй — когда используется конструкция $this->endWidget. Если необходимо получить и обработать содержимое, заключённое между вызовами этих двух функций, то можно запустить буферизацию вывода в CWidget::init и получать сохранённый вывод для дальнейшей обработки в методе CWidget::run.

Когда виджет используется на странице, он обычно подключает CSS стили, JavaScript файлы и прочие файлы ресурсов. Файлы такого рода называются ресурсы, поскольку они хранятся вместе с файлом класса виджета и, как правило, не доступны веб-пользователям. Для того чтобы они стали доступны пользователям, их необходимо опубликовать, используя CWebApplication::assetManager, как показано во фрагменте кода выше. Помимо этого, если необходимо подключить файлы CSS стилей или JavaScript на текущей странице, их необходимо зарегистрировать посредством CClientScript:

class MyWidget extends CWidget
{
    protected function 
registerClientScript()
    {
        
// …подключаем здесь файлы CSS или JavaScript…
        
$cs=Yii::app()->clientScript;
        
$cs->registerCssFile($cssFile);
        
$cs->registerScriptFile($jsFile);
    }
}

Виджет также может иметь собственные файлы представлений. В этом случае необходимо создать директорию views внутри директории, содержащей файл класса виджета, и поместить в неё все файлы представлений. Для подключения представлений виджета в его классе используется конструкция $this->render('ViewName'), аналогичная соответствующему методу контроллера.

Действие #

Действие должно расширять класс CAction или производные от него. IAction::run — основной метод, который необходимо реализовать для действия.

Фильтр #

Фильтр должен расширять класс CFilter или производные от него. Основными методами, которые необходимо реализовать, являются CFilter::preFilter и CFilter::postFilter. Первый вызывается до выполнения действия, второй — после.

class MyFilter extends CFilter
{
    protected function 
preFilter($filterChain)
    {
        
// применяется до выполнения действия
        
return true// значение false возвращается, если действие не должно выполняться
    
}

    protected function 
postFilter($filterChain)
    {
        
// применяется после завершения выполнения действия
    
}
}

Параметр $filterChain — экземпляр класса CFilterChain, содержащий информацию о действии, к которому применяются фильтры в настоящий момент.

Контроллер #

Контроллер, распространяемый как расширение, должен наследовать класс CExtController, а не класс CController. Основной причиной этого является то, что для класса CController предполагается, что файлы представлений располагаются в application.views.ControllerID, а для CExtController считается, что файлы представлений находятся в директории views, расположенной в той же директории, что и файл класса этого контроллера. Очевидно, что расширение-контроллер удобнее распространять, когда все файлы расширения собраны в одном месте.

Валидатор #

Валидатор должен расширять класс CValidator и реализовывать его метод CValidator::validateAttribute.

class MyValidator extends CValidator
{
    protected function 
validateAttribute($model,$attribute)
    {
        
$value=$model->$attribute;
        if(
$value has error)
            
$model->addError($attribute,$errorMessage);
    }
}

Команда консоли #

Консольная команда должна расширять класс CConsoleCommand и реализовывать его метод CConsoleCommand::run. При желании можно переопределить метод CConsoleCommand::getHelp, который отвечает за информационную справку по команде.

class MyCommand extends CConsoleCommand
{
    public function 
run($args)
    {
        
// $args — массив аргументов, переданных с командой
    
}

    public function 
getHelp()
    {
        return 
'Usage: how to use this command';
    }
}

Модуль #

Информация о порядке создания и использования модулей представлена в разделе Модуль.

Если сформулировать требования в общем виде, то модуль должен быть самодостаточным, файлы ресурсов (CSS, JavaScript, изображения), используемые модулем, должны распространяться вместе с модулем, а сам модуль должен публиковать ресурсы, чтобы они были доступны для веб-пользователей.

Компонент общего вида #

Разработка компонента общего вида аналогична написанию класса. Компонент, как и модуль, должен быть самодостаточен и удобен для использования другими разработчиками.


Зачем реклама?