Начиная с версии 1.1.2, в состав Yii входит веб-инструмент для генерации кода,
называемый Gii. Он заменяет существовавший до этого консольный генератор
yiic shell
. В данном разделе описано, как использовать Gii и как расширить его
для ускорения разработки.
Gii является модулем и должен быть использован в составе существующего приложения Yii. Для использования Gii необходимо отредактировать файл конфигурации приложения следующим образом:
return array(
…
'modules'=>array(
'gii'=>array(
'class'=>'system.gii.GiiModule',
'password'=>'задайте свой пароль',
// 'ipFilters'=>array(…список IP…),
// 'newFileMode'=>0666,
// 'newDirMode'=>0777,
),
),
);
Выше мы объявили модуль с именем gii
и классом GiiModule. Также мы задали
пароль, который будет использоваться для доступа к Gii.
По умолчанию, в целях безопасности, Gii доступен только для localhost. Если необходимо дать доступ к нему с других компьютеров, нужно задать свойство GiiModule::ipFilters как показано в коде выше.
Так как Gii будет генерировать и сохранять новые файлы с кодом в существующее приложение, необходимо убедиться в том, что процесс веб-сервера имеет на это права. Показанные выше свойства GiiModule::newFileMode и GiiModule::newDirMode содержат права, с которыми будут создаваться файлы и директории.
Примечание: Gii является инструментом разработчика. Поэтому он должен быть установлен исключительно на компьютере или сервере разработчика. Так как он может генерировать новые скрипты PHP, необходимо уделить особое внимание безопасности (пароль, IP фильтры).
Теперь можно запустить Gii по URL http://hostname/path/to/index.php?r=gii
, где
http://hostname/path/to/index.php
— URL вашего приложения.
Если существующее приложение использует формат URL path
(см. красивые адреса URL), мы можем запустить Gii по URL
http://hostname/path/to/index.php/gii
. Может понадобиться добавить следующие правила
URL перед уже существующими:
'components'=>array(
…
'urlManager'=>array(
'urlFormat'=>'path',
'rules'=>array(
'gii'=>'gii',
'gii/<controller:\w+>'=>'gii/<controller>',
'gii/<controller:\w+>/<action:\w+>'=>'gii/<controller>/<action>',
…существующие правила…
),
),
)
В составе Gii есть готовый набор генераторов кода. Каждый генератор отвечает за свой тип кода. К примеру, генератор контроллера создаёт класс контроллера вместе с несколькими шаблонами отображения; генератор модели создаёт класс ActiveRecord для определённой таблицы БД.
Последовательность работы с генератором следующая:
Preview
для предварительной оценки генерируемого кода.
Вы увидите таблицу файлов, которые будут сгенерированы и сможете просмотреть их
код;Generate
для создания файлов;Примечание: после генерации модели стоит проверить и скорректировать метод
rules
так как структура базы данных часто не содержит достаточно данных о требованиях валидации.
Несмотря на то, что включённые в состав Gii генераторы создают достаточно функциональный код, часто требуется его немного изменить или создать новый генератор по своему вкусу и потребностям. К примеру, нам может понадобиться изменить стиль генерируемого кода или добавить поддержку нескольких языков. Всё это может быть легко реализовано через Gii.
Gii можно расширять двумя способами: изменяя существующие шаблоны кодогенераторов и создавая свои генераторы.
Генератор кода размещается в директории, чьё имя является именем генератора. Директория обычно содержит:
model/ корневая директория генератора модели ModelCode.php модель, используемая для генерации кода ModelGenerator.php контроллер кодогенератора views/ отображения генератора index.php шаблон по умолчанию templates/ шаблоны кода default/ набор шаблонов 'default' model.php шаблон для генерации класса модели
Gii ищет генераторы в списке директорий, указанных в свойстве GiiModule::generatorPaths. В том случае, если необходимо добавить свои генераторы, следует настроить приложение следующим образом:
return array(
'modules'=>array(
'gii'=>array(
'class'=>'system.gii.GiiModule',
'generatorPaths'=>array(
'common.gii', // псевдоним пути
),
),
),
);
Приведённые выше настройки заставляют Gii искать генераторы в директории
с псевдонимом common.gii
в дополнение к стандартным system.gii.generators
и application.gii
.
Возможно иметь несколько одноимённых генераторов, если у них разные пути поиска. В этом случае будет использоваться генератор, путь поиска которого указан выше в GiiModule::generatorPaths.
Изменение шаблонов кода — самый простой и самый распространённый путь расширения Gii. Мы будем использовать примеры для того, чтобы описать, как изменить шаблоны кода. Допустим, нам необходимо изменить код, создаваемый генератором модели.
Сначала мы создаём директорию protected/gii/model/templates/compact
. Здесь model
означает, что мы собираемся перекрыть генератор модели по умолчанию.
А templates/compact
— что мы добавляем новый набор шаблонов кода compact
.
После этого мы добавляем в настройки приложения в свойство GiiModule::generatorPaths
значение application.gii
, как показано в предыдущем подразделе.
Теперь открываем страницу генератора модели. Щёлкаем на поле Code Template
.
Вы должны увидеть выпадающий список, содержащий нашу только что созданную директорию
шаблонов compact
. Тем не менее, если мы выберем этот шаблон, будет выведена
ошибка. Происходит это потому, что в наборе compact
ещё нет самих шаблонов кода.
Скопируем файл framework/gii/generators/model/templates/default/model.php
в
protected/gii/model/templates/compact
. Если попробовать сгенерировать код
с набором compact
ещё раз, генерация должна пройти успешно. Тем не менее,
генерируемый код ничем не отличается от кода, получаемого из набора default
.
Время сделать некоторые изменения.
Откроем файл protected/gii/model/templates/compact/model.php
. Данный файл будет
использован как шаблон отображения, что означает, что он может содержать
выражения и код PHP. Изменим шаблон таким образом, что метод attributeLabels()
генерируемого кода будет использовать Yii::t()
для перевода заголовков полей:
public function attributeLabels() { return array( foreach($labels as $name=>$label): echo "'$name' => Yii::t('application', '$label'),\n"; endforeach; ); }
В каждом шаблоне кода у нас есть доступ к некоторым предопределённым переменным,
таким как, например, $labels
. Эти переменные задаются соответствующим генератором
кода. Разные генераторы могут предоставлять шаблонам различные наборы переменных.
Стоит внимательно изучить описание шаблонов кода по умолчанию.
В этом подразделе мы покажем, как реализовать новый генератор, который сможет создавать новые классы виджетов.
Сначала создадим директорию protected/gii/widget
. В ней создадим следующие файлы:
WidgetGenerator.php
: содержит класс контроллера WidgetGenerator
, который
является входной точкой генератора виджетов.WidgetCode.php
: содержит класс модели WidgetCode
, который отвечает за
логику генерации кода.views/index.php
: отображение, содержащее форму ввода генератора.templates/default/widget.php
: шаблон кода по умолчанию для генерации класса
виджета.WidgetGenerator.php
Файл WidgetGenerator.php
предельно простой. Он содержит лишь следующий код:
class WidgetGenerator extends CCodeGenerator
{
public $codeModel='application.gii.widget.WidgetCode';
}
Здесь мы описываем, что генератор будет использовать класс модели, чей псевдоним
пути application.gii.widget.WidgetCode
. Класс WidgetGenerator
наследуется
от CCodeGenerator, реализующего большое количество функций, включая
действия контроллера, необходимые для координации процесса генерации кода.
WidgetCode.php
Файл WidgetCode.php
содержит класс модели WidgetCode
, в котором реализована
логика генерации класса виджета на основе полученных от пользователя параметров.
В данном примере будем считать, что единственное, что вводит пользователь —
имя класса виджета. WidgetCode
выглядит следующим образом:
class WidgetCode extends CCodeModel
{
public $className;
public function rules()
{
return array_merge(parent::rules(), array(
array('className', 'required'),
array('className', 'match', 'pattern'=>'/^\w+$/'),
));
}
public function attributeLabels()
{
return array_merge(parent::attributeLabels(), array(
'className'=>'Widget Class Name',
));
}
public function prepare()
{
$path=Yii::getPathOfAlias('application.components.' . $this->className) . '.php';
$code=$this->render($this->templatepath.'/widget.php');
$this->files[]=new CCodeFile($path, $code);
}
}
Класс WidgetCode
наследуется от CCodeModel. Как и в обычном классе модели, в
данном классе мы реализуем методы rules()
и attributeLabels()
для валидации
ввода и генерации подписей полей соответственно. Стоит отметить, что так как
базовый класс CCodeModel уже описывает некоторое количество правил валидации
и названий подписей, то мы должны объединить их с нашими правилами и подписями.
Метод prepare()
подготавливает код к генерации. Главная задача метода — подготовить
список объектов CCodeFile, каждый из которых представляет будущий файл с кодом.
В нашем примере необходимо создать всего один объект CCodeFile, представляющий
класс виджета, который будет сгенерирован в директории protected/components
.
Для непосредственной генерации кода используется метод CCodeFile::render.
Данный метод содержит PHP-шаблон кода и возвращает сгенерированный код.
views/index.php
После реализации контроллера (WidgetGenerator
) и модели (WidgetCode
)
самое время заняться отображением views/index.php
:
<h1>Генератор виджета</h1> $form=$this->beginWidget('CCodeForm', array('model'=>$model)); <div class="row"> echo $form->labelEx($model,'className'); echo $form->textField($model,'className',array('size'=>65)); <div class="tooltip"> Класс виджета должен содержать только буквы. </div> echo $form->error($model,'className'); </div> $this->endWidget();
В данном коде мы отображаем форму, используя виджет CCodeForm. В этой форме мы
показываем поле для ввода атрибута className
модели WidgetCode
.
При создании формы мы можем использовать две замечательные возможности CCodeForm. Одна — подсказки для полей. Вторая — запоминание введённых значений.
Если вы использовали один из стандартных генераторов кода, вы могли заметить красивые
всплывающие подсказки, появляющиеся рядом с полем при получении им фокуса. Использовать
данную возможность очень легко: достаточно после поля вставить div
с CSS классом tooltip
.
Для некоторых полей полезно запомнить последнее верное значение и тем самым позволив пользователю не вводить значения повторно каждый раз, когда он использует генератор. Примером может служить поле ввода базового класса контроллера в стандартном генераторе. Такие поля изначально отображаются как подсвеченный статичный текст. При щелчке они превращаются в поля ввода.
Для того, чтобы сделать поле запоминаемым, необходимо сделать две вещи.
Во-первых, нужно описать правило валидации sticky
для соответствующего атрибута
модели. К примеру, для стандартного генератора контроллера используется приведённое
ниже правило для запоминания атрибутов baseClass
и actions
:
public function rules()
{
return array_merge(parent::rules(), array(
…
array('baseClass, actions', 'sticky'),
));
}
Во-вторых, в отображении необходимо добавить CSS класс sticky
контейнеру div
поля ввода:
<div class="row sticky">
…поле ввода…
</div>
templates/default/widget.php
Наконец, мы создаём шаблон кода templates/default/widget.php
. Как было описано
ранее, он используется как PHP-шаблон отображения. В шаблоне кода мы всегда
можем обратиться к переменной $this
, которая содержит экземпляр модели кода.
В нашем примере $this
содержит объект WidgetModel
. Таким образом, мы можем
получить введённый пользователем класс виджета через $this->className
.
echo '<?php'; class echo $this->className; extends CWidget { public function run() { } }
На этом реализация генератора кода завершена. Обратиться к нему можно по
URL http://hostname/path/to/index.php?r=gii/widget
.
Found a typo or you think this page needs improvement?
Edit it on github !
Signup or Login in order to comment.