
Оскільки створення розширень передбачає їх використання сторонніми розробниками, процес створення вимагає додаткових зусиль. Нижче наведені основні правила, яких необхідно дотримуватися при створенні розширень:
Нижче ми розповімо про те, як створити нове розширення відповідно до класифікації, наведеної в огляді. Пояснення в рівній мірі поширюються і на розширення, які використовуються виключно у власних проектах.
Компонент додатка повинен реалізовувати інтерфейс 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 буде автоматично привласнено поточний час.
phpclass 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, щоб при використанні віджету не була потрібна постійна конфігурація, наступним чином:
phpclass 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:
phpclass 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. Перший викликається до виконання дії, другий - після.
phpclass 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.
phpclass MyValidator extends CValidator { protected function validateAttribute($model,$attribute) { $value=$model->$attribute; if($value has error) $model->addError($attribute,$errorMessage); } }
Консольна команда повинна розширювати клас CConsoleCommand і реалізовувати його метод CConsoleCommand::run. При бажанні можна перевизначити метод CConsoleCommand::getHelp, який відповідає за інформаційну довідку команди.
phpclass MyCommand extends CConsoleCommand { public function run($args) { // $args — масив аргументів, переданих з командою } public function getHelp() { return 'Usage: how to use this command'; } }
Інформація про порядок використання і створення модулів представлена у розділі Модуль.
Якщо сформулювати вимоги у загальному вигляді, то модуль повинен бути самодостатнім, файли ресурсів (CSS, JavaScript, зображення), що використовуються модулем, повинні поширюватися разом з модулем, а сам модуль повинен публікувати ресурси, щоб вони були доступні для веб-користувачів.
Розробка загального компонента аналогічна написання класу. Компонент, як і модуль, повинен бути самодостатнім і зручним для використання розробниками.
class MyFilter extends CFilter
{
protected function preFilter($filterChain)
{
// застосовується до виконання дії
return true; // значення false повертається, якщо дія не повинна виконуватися
}
protected function postFilter($filterChain)
{
// застосовується після завершення виконання дії
}
}