Автоматическая генерация кода ============================= Начиная с версии 1.1.2, в состав Yii входит веб-инструмент для генерации кода, называемый *Gii*. Он заменяет существовавший до этого консольный генератор `yiic shell`. В данном разделе описано, как использовать Gii и как расширить его для ускорения разработки. Использование Gii ----------------- Gii является модулем и должен быть использован в составе существующего приложения Yii. Для использования Gii необходимо отредактировать файл конфигурации приложения следующим образом: ~~~ [php] 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] содержат права, с которыми будут создаваться файлы и директории. > Note|Примечание: Gii является инструментом разработчика. Поэтому он должен быть > установлен исключительно на компьютере или сервере разработчика. Так как > он может генерировать новые скрипты PHP, необходимо уделить особое внимание > безопасности (пароль, IP фильтры). Теперь можно запустить Gii по URL `http://hostname/path/to/index.php?r=gii`, где `http://hostname/path/to/index.php` — URL вашего приложения. Если существующее приложение использует формат URL `path` (см. [красивые адреса URL](/doc/guide/topics.url)), мы можем запустить Gii по URL `http://hostname/path/to/index.php/gii`. Может понадобиться добавить следующие правила URL перед уже существующими: ~~~ [php] 'components'=>array( … 'urlManager'=>array( 'urlFormat'=>'path', 'rules'=>array( 'gii'=>'gii', 'gii/'=>'gii/', 'gii//'=>'gii//', …существующие правила… ), ), ) ~~~ В составе Gii есть готовый набор генераторов кода. Каждый генератор отвечает за свой тип кода. К примеру, генератор контроллера создаёт класс контроллера вместе с несколькими шаблонами отображения; генератор модели создаёт класс ActiveRecord для определённой таблицы БД. Последовательность работы с генератором следующая: 1. Зайти на страницу генератора; 2. Заполнить поля, которые задают параметры генерируемого кода. К примеру, для генерации модуля необходимо указать его ID; 3. Нажать кнопку `Preview` для предварительной оценки генерируемого кода. Вы увидите таблицу файлов, которые будут сгенерированы и сможете просмотреть их код; 4. Нажать кнопку `Generate` для создания файлов; 5. Просмотреть журнал генерации кода. > Note|Примечание: после генерации модели стоит проверить и скорректировать метод `rules` так как структура базы данных часто не содержит достаточно данных о требованиях валидации. Расширение Gii -------------- Несмотря на то, что включённые в состав Gii генераторы создают достаточно функциональный код, часто требуется его немного изменить или создать новый генератор по своему вкусу и потребностям. К примеру, нам может понадобиться изменить стиль генерируемого кода или добавить поддержку нескольких языков. Всё это может быть легко реализовано через Gii. Gii можно расширять двумя способами: изменяя существующие шаблоны кодогенераторов и создавая свои генераторы. ###Структура кодогенератора Генератор кода размещается в директории, чьё имя является именем генератора. Директория обычно содержит: ~~~ model/ корневая директория генератора модели ModelCode.php модель, используемая для генерации кода ModelGenerator.php контроллер кодогенератора views/ отображения генератора index.php шаблон по умолчанию templates/ шаблоны кода default/ набор шаблонов 'default' model.php шаблон для генерации класса модели ~~~ ###Путь поиска генераторов Gii ищет генераторы в списке директорий, указанных в свойстве [GiiModule::generatorPaths]. В том случае, если необходимо добавить свои генераторы, следует настроить приложение следующим образом: ~~~ [php] 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()` для перевода заголовков полей: ~~~ [php] public function attributeLabels() { return array( $label): ?> Yii::t('application', '$label'),\n"; ?> ); } ~~~ В каждом шаблоне кода у нас есть доступ к некоторым предопределённым переменным, таким как, например, `$labels`. Эти переменные задаются соответствующим генератором кода. Разные генераторы могут предоставлять шаблонам различные наборы переменных. Стоит внимательно изучить описание шаблонов кода по умолчанию. ###Создание новых генераторов В этом подразделе мы покажем, как реализовать новый генератор, который сможет создавать новые классы виджетов. Сначала создадим директорию `protected/gii/widget`. В ней создадим следующие файлы: * `WidgetGenerator.php`: содержит класс контроллера `WidgetGenerator`, который является входной точкой генератора виджетов. * `WidgetCode.php`: содержит класс модели `WidgetCode`, который отвечает за логику генерации кода. * `views/index.php`: отображение, содержащее форму ввода генератора. * `templates/default/widget.php`: шаблон кода по умолчанию для генерации класса виджета. #### Реализация `WidgetGenerator.php` Файл `WidgetGenerator.php` предельно простой. Он содержит лишь следующий код: ~~~ [php] class WidgetGenerator extends CCodeGenerator { public $codeModel='application.gii.widget.WidgetCode'; } ~~~ Здесь мы описываем, что генератор будет использовать класс модели, чей псевдоним пути `application.gii.widget.WidgetCode`. Класс `WidgetGenerator` наследуется от [CCodeGenerator], реализующего большое количество функций, включая действия контроллера, необходимые для координации процесса генерации кода. #### Реализация `WidgetCode.php` Файл `WidgetCode.php` содержит класс модели `WidgetCode`, в котором реализована логика генерации класса виджета на основе полученных от пользователя параметров. В данном примере будем считать, что единственное, что вводит пользователь — имя класса виджета. `WidgetCode` выглядит следующим образом: ~~~ [php] 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`: ~~~ [php]

Генератор виджета

beginWidget('CCodeForm', array('model'=>$model)); ?>
labelEx($model,'className'); ?> textField($model,'className',array('size'=>65)); ?>
Класс виджета должен содержать только буквы.
error($model,'className'); ?>
endWidget(); ?> ~~~ В данном коде мы отображаем форму, используя виджет [CCodeForm]. В этой форме мы показываем поле для ввода атрибута `className` модели `WidgetCode`. При создании формы мы можем использовать две замечательные возможности [CCodeForm]. Одна — подсказки для полей. Вторая — запоминание введённых значений. Если вы использовали один из стандартных генераторов кода, вы могли заметить красивые всплывающие подсказки, появляющиеся рядом с полем при получении им фокуса. Использовать данную возможность очень легко: достаточно после поля вставить `div` с CSS классом `tooltip`. Для некоторых полей полезно запомнить последнее верное значение и тем самым позволив пользователю не вводить значения повторно каждый раз, когда он использует генератор. Примером может служить поле ввода базового класса контроллера в стандартном генераторе. Такие поля изначально отображаются как подсвеченный статичный текст. При щелчке они превращаются в поля ввода. Для того, чтобы сделать поле запоминаемым, необходимо сделать две вещи. Во-первых, нужно описать правило валидации `sticky` для соответствующего атрибута модели. К примеру, для стандартного генератора контроллера используется приведённое ниже правило для запоминания атрибутов `baseClass` и `actions`: ~~~ [php] public function rules() { return array_merge(parent::rules(), array( … array('baseClass, actions', 'sticky'), )); } ~~~ Во-вторых, в отображении необходимо добавить CSS класс `sticky` контейнеру `div` поля ввода: ~~~ [php]
…поле ввода…
~~~ #### Реализация `templates/default/widget.php` Наконец, мы создаём шаблон кода `templates/default/widget.php`. Как было описано ранее, он используется как PHP-шаблон отображения. В шаблоне кода мы всегда можем обратиться к переменной `$this`, которая содержит экземпляр модели кода. В нашем примере `$this` содержит объект `WidgetModel`. Таким образом, мы можем получить введённый пользователем класс виджета через `$this->className`. ~~~ [php] class className; ?> extends CWidget { public function run() { } } ~~~ На этом реализация генератора кода завершена. Обратиться к нему можно по URL `http://hostname/path/to/index.php?r=gii/widget`.