Development

Documentation/ru_RU/book/1.0/14-Generators

You must first sign up to be able to contribute.

Version 10 (modified by Sergei.Vasilyev, 10 years ago)
--

Глава 14 - Генераторы кода

Этот перевод выполнил Сергей Васильев. Вы можете связаться со мной по e-mail symfony2007 at devoffice dot com. Список переведеных мной терминов с объяснением их значения:

  • administration - админка. Часть веб-сайта, доступная лишь обслуживающему персоналу и предоставляющая возможности манипулирования данными;
  • scaffolding - каркас. Буквально означает "строительные леса";

Многие приложения основаны на информации, хранимой в базе данных, и предлагают интерфейс для доступа к ней. Симфони автоматизирует рутинную задачу создания модуля, предоставляющего возможности манипулирования данными. Если ваша объектная модель правильно определена, симфони для этого может даже сгенерировать целый сайт. Эта глава расскажет вам о двух генераторах, встроенных в симфони: генератор каркасов и генератор админок. Последний полагается на специальный конфигурационный файл с совершенным синтаксисом, так что большая часть этой главы описывает различные возможности генератора администрирования.

Генерация кода, основанного на модели

В веб-приложении операции доступа к данным могут быть разделены на следующие:

  • Создание записи - Creation
  • Получение записей - Retrieval
  • Обновление записи (т.е. модификация её полей) - Update
  • Удаление записи - Deletion

Эти операции носят настолько общий характер, что для них придуман специальный акроним: CRUD. Многие веб-страницы могут быть сведены к одной из этих операций. Например, в приложении-форуме, список последних публикаций - это операция получения записей, ответ на публикацию соответствует операции создания записи.

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

Все задачи генерации кода основаны на модели создания целого модуля, как результата одного вызова команды symfony в следующей форме:

> symfony <TASK_NAME> <APP_NAME> <MODULE_NAME> <CLASS_NAME>

Задачи генерации кода - это propel-init-crud, propel-generate-crud, и propel-init-admin.

Каркасы и админки

При разработке приложения генерация кода может быть использована в двух различных целях:

  • для создания каркаса, состоящего из действий и шаблонов, необходимых для выполнения операций CRUD с данной таблицей. Код минимален, так как подразумевается, что он будет служить основой для дальнейшей разработки. Этот каркас затем должен быть адаптирован к требованиям вашей логики и представления. Как правило, каркасы используются во время разработки, что бы предоставить доступ к базе данных, построить прототип, или создать модуль, преимущественно ориентированный на таблицу.

  • для создания изощренного интерфейса манипулирования данными, предназначенного для для внутреннего администрирования сайта (админка). Админки отличаются от каркасов, потому что их код не предполагается модифицировать вручную. Они могут быть настроены, расширены или собраны из частей через конфигурирование или наследование. Их способ представления важен, и они используют дополнительные возможности в виде сортировки, постраничной разбивки и фильтров. Админка может быть создана и передана клиенту как законченная часть программного продукта.

Опции команды symfony используют слово crud для создания каркасов, и admin для админок.

Инициализация или генерация кода

Симфони предлагает два способа, что бы сгенерировать код: или через наследование (init), или через генерацию кода (generate).

Вы можете инициализировать модуль, то есть, создать пустые классы, которые порождены от фреймворка. Это скрывает PHP-код действий и шаблонов таким образом, что бы избежать его модификации. Это полезно, если структура ваших данных не окончательна, или если вам нужно быстро получить интерфейс к базе данных для манипулирования данными. В этом случае исполняемый код находится вне вашего приложения, в кеше. В командной строке задачи такого типа обозначаются как propel-init-.

Код инициализированного действия пуст. Например, первоначально модуль article может содержать действия вроде этого:

[php]
class articleActions extends autoarticleActions
{
}

С другой стороны, вы также можете генерировать код действий и шаблонов таким образом, что он может быть модифицирован. Окончательный модуль будет независим от классов фреймворка, и не сможет изменяться при помощи конфигурационных файлов. Для задач такого типа ключ командной строки начинается с propel-generate-.

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

Пример модели данных

Примеры этой главы, основанные на хорошо известном образце веб-приложения -- блога, с которым вы уже знакомились в Главе 8, покажут вам возможности генераторов симфони. Этот блог содержит классы Article (Статьи) и Comment (Комментарии). Пример 14-1 и Рисунок 14-1 напомнят вам схему его данных.

Пример 14-1 - schema.yml приложения-блога

propel:
  blog_article:
    _attributes: { phpName: Article }
    id:
    title:       varchar(255)
    content:     longvarchar
    created_at:
  blog_comment:
    _attributes: { phpName: Comment }
    id:
    article_id:
    author:      varchar(255)
    content:     longvarchar
    created_at:

Рисунок 14-1 - Модель данных

Example data model

Симфони будет использовать схему и интерпретировать её атрибуты, что бы генерировать каркас или админку.

TIP Что бы получить от этой главы как можно больше пользы, вам следует выполнять все примеры. Вы лучше поймете, что генерирует симфони, и что можно сделать с сгенерированным кодом, если вы выполните каждый шаг, описанный в примерах. Так что создайте описанную структуру данных, что бы на её основе создать БД с таблицами blog_article и blog_comment и наполнить их данными.

Каркасы

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

Генерация каркаса

Что бы сгенерировать каркас для модуля article, основанного на классе модели Article, введите следующую команду:

> symfony propel-generate-crud myapp article Article

Симфони прочитает определение класса Article в schema.yml и создаст набор шаблонов и действий, основанный на нем, в каталоге myapp/modules/article/.

Сгенерированный модуль содержит три представления. Представление list, которое является представлением по умолчанию, показывает строки таблицы blog_article. Просмотр http://localhost/myapp_dev.php/article, показан на Рисунке 14-2.

Рисунок 14-2 - Представление list модуля article

list view of the article module

Щелчок на идентификаторе статьи покажет представление show. Это будет детальное представление одной строки на одной странице, как показано на рисунке 14-3.

Рисунок 14-3 - Представление show модуля article

show view of the article module

Представление edit, показанное на Рисунке 14-4, вызывается ссылкой edit (для редактирования существующей информации о статье) или ссылкой create (для создания новой статьи).

Используя этот модуль, вы можете создавать новые статьи и изменять или удалять существующие. Сгенерированный код - хорошее начало дальнейшей разработки. Пример 14-2 показывает список сгенерированных действий и шаблонов этого нового модуля.

Рисунок 14-4 - Представление edit модуля article

edit view of the article module

Пример 14-2 - Список сгенерированных в myapp/modules/article/ элементов CRUD

// In actions/actions.class.php
index           // Forwards to the list action below
list            // Displays the list of all the records of the table
show            // Displays the lists of all columns of a record
edit            // Displays a form to modify the columns of a record
update           // Action called by the edit action form
delete           // Deletes a record
create           // Creates a new record

// In templates/
editSuccess.php  // Record edition form (edit view)
listSuccess.php  // List of all records (list view)
showSuccess.php  // Detail of one record (show view)

Логика этих модулей ясна и довольно проста. Что бы понять её, просмотрите код сгенерированного класса действия в Примере 14-3.

Пример 14-3 - Сгенерированный класс действия, в myapp/modules/article/actions/actions.class.php

[php]
class articleActions extends sfActions
{
  public function executeIndex()
  {
    return $this->forward('article', 'list');
  }

  public function executeList()
  {
    $this->articles = ArticlePeer::doSelect(new Criteria());
  }

  public function executeShow()
  {
    $this->article = ArticlePeer::retrieveByPk($this->getRequestParameter('id'));
    $this->forward404Unless($this->article);
  }
  ...

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

Инициализация каркаса

Инициализация каркаса наиболее полезна, когда вам нужно проверить, что вы получить доступ к данным в базе. Такие каркасы можно быстро инициализировать и так же быстро удалить, как только вы убедитесь, что всё работает правильно.

Что бы инициировать каркас Propel и создать модуль article, который будет работать с записями класса Article, введите следующую команду:

> symfony propel-init-crud myapp article Article

Теперь вы можете вызвать представление list, используя стандартное действие:

http://localhost/myapp_dev.php/article

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

Если вы посмотрите код в только что созданном файле actions.class.php , вы увидите, что он пуст: всё наследуется от автоматически генерируемого класса. То же самое верно и для шаблонов: в папке templates вообще нет шаблонов. Код инициализированных действий и шаблонов такой же, как и для генерируемого каркаса, но он располагается только в кеше приложения (каталог myproject/cache/myapp/prod/module/autoArticle/).

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

Админки

Симфони может генерировать более продвинутые модули, основанные на определениях классов модели из файла schema.yml, предназначенные для внутренних интерфейсов ваших приложений. Вы можете создать администрирование сайта, целиком используя генерируемые модули. Примеры этого раздела покажут вам модули администрирования, добавленные к приложению backend. Если ваш проект ещё не содержит приложения backend, создайте его при помощи такой команды:

> symfony init-app backend

Модули админки интерпретируют модель, используя специальный конфигурационный файл, называемый generator.yml, который может быть изменён для расширения сгенерированных компонент и интерфейса. Такие модули широко используют механизмы, описанные в предыдущих главах (обрамление(layout), валидацию, навигацию(routing), конфигурирование, автозагрузку и т.д.). Конечно, вы можете переопределить сгенерированные действия и шаблоны, что бы интегрировать ваши собственные наработки в сгенерированную админку, но использование разнообразных настроек generator.yml позволит вам свести использование PHP-кода к минимуму.

Иниализациация модуля админки

В симфони, вы строите админку на основе модулей. Модуль генерируется на основе объекта Propel, используя команду propel-init-admin, которая использует синтаксис, аналогичный тому, что используется для инициации каркаса:

> symfony propel-init-admin backend article Article

Этого вызова достаточно для создания в приложении backend модуля article, основанного на определении класса Article, и он доступен по адресу:

http://localhost/backend.php/article

Внешний вид и поведение сгенерированного модуля, показанного на Рисунках 14-5 и 14-6, достаточно сложны, что бы использовать его в коммерческом приложении.

Рисунок 14-5 - Представление list модуля article приложения backend

Представление list модуля article приложения backend

Рисунок 14-6 - Представление edit модуля article приложения backend

Представление edit модуля article приложения backend

Разница между интерфейсом каркаса и интерфейсом админки еще не слишком заметна, но конфигурирование позволит вам усовершенствовать изначальное представление, добавить многие дополнительные возможности, не написав при этом ни единой строки кода PHP.

NOTE Админки могут быть только инициализированы, но не сгенерированы.

Окинем взглядом сгенерированный код

Код модуля админки Article, расположенный в apps/backend/modules/article/, пуст, так как он всего лишь инициирован. Лучший способ просмотреть сгенерированный код этого модуля - это походить по его страницам в броузере, а затем посмотреть содержимое каталога cache. Пример 14-4 показывает список сгенерированных действий и шаблонов, найденных в кеше.

Пример 14-4 - Сгенерированные элементы админки в cache/backend/ENV/modules/article/

// В файле actions/actions.class.php
create           // Отсылает к редактированию
delete            // Удаляет запись
edit             // Показывает форму для изменения полей записи
                 // And handles the form submission
index            // Отсылает к списку
list             // Показывает список всех записей в таблице
save             // Forwards to edit

// В каталоге templates/
_edit_actions.php
_edit_footer.php
_edit_form.php
_edit_header.php
_edit_messages.php
_filters.php
_list.php
_list_actions.php
_list_footer.php
_list_header.php
_list_messages.php
_list_td_actions.php
_list_td_stacked.php
_list_td_tabular.php
_list_th_stacked.php
_list_th_tabular.php
editSuccess.php
listSuccess.php

Видно, что модуль состоит в основном из двух представлений - edit and list/. Если вы посмотрите в код, то найдете его очень модульным, читабельным и расширяемым.

Введение в конфигурационный файл generator.yml

Основное различие между каркасами и админками (кроме того, что админки не имеют действия show) заключается в том, что админки полагаются на параметры, заданные в файле generator.yml. Что бы посмотреть конфигурацию только что созданного модуля админки, откройте файл generator.yml, который находится в папке backend/modules/article/config/generator.yml (показан в Примере 14-5).

Пример 14-5 - Типовая сгенерированная конфигурация , в backend/modules/article/config/generator.yml

generator:
  class:              sfPropelAdminGenerator
  param:
    model_class:      Article
    theme:            default

Этой конфигурации достаточно для базовой админки. Параметры для кастомизации интерфейса добавляются под ключом param, после строки theme (это значит, что все строки, добавленные в конец файла generator.yml, должны начинаться как минимум с четырёх последовательных пробелов для правильного выравнивания). Пример 14-16 показывает измененный файл generator.yml.

Пример 14-6 - Дополненная конфигурация генератора

generator:
  class:              sfPropelAdminGenerator
  param:
    model_class:      Article
    theme:            default

    fields:
      author_id:      { name: Article author }

    list:
      title:          List of all articles
      display:        [title, author_id, category_id]
      fields:
        published_on: { params: date_format='dd/MM/yy' }
      layout:         stacked
      params:         |
        %%is_published%%<strong>%%=title%%</strong><br /><em>by %%author%%
        in %%category%% (%%published_on%%)</em><p>%%content_summary%%</p>
      filters:        [title, category_id, author_id, is_published]
      max_per_page:   2

    edit:
      title:          Editing article "%%title%%"
      display:
        "Post":       [title, category_id, content]
        "Workflow":   [author_id, is_published, created_on]
      fields:
        category_id:  { params: disabled=true }
        is_published: { type: plain}
        created_on:   { type: plain, params: date_format='dd/MM/yy' }
        author_id:    { params: size=5 include_custom=>> Choose an author << }
        published_on: { credentials:  }
        content:      { params: rich=true tinymce_options=height:150 }

Следующие разделы подробно объяснят все параметры, использованные в этом конфигурационном файле.

Конфигурация генератора

Конфигурационный файл генератора - очень мощное средство, которое позволяет изменить генерируемую админку многими способами. Полное описание его синтаксиса делает эту главу одной из наибольших в этой книге. Веб-сайт симфони предоставляет ещё один ресурс, который поможет вам изучить этот синтаксис: шпаргалку по генератору админок, воспроизведенную на рисунке 14-7. Скачайте её с http://www.symfony-project.com/uploads/assets/sfAdminGeneratorRefCard.pdf, и расположите где-нибудь рядом, пока будете изучать примеры этой главы.

The examples of this section will tweak the article administration module, as well as the comment administration module, based on the Comment class definition. Create the latter with the propel-init-admin task:

> symfony propel-init-admin backend comment Comment

Рисунок 14-7 - The administration generator cheat sheet

The administration generator cheat sheet

Поля - Fields

По умолчанию, столбцы представления list и поля представления edit - это столбцы, определенные в файле schema.yml. При помощи конфигурации генератора, вы можете выбрать, какие поля будут показаны, какие - скрыты, и добавить свои собственные поля, даже если они не имеют прямого соответствия в объектной модели.

Настройки полей - Field Settings

Генератор админок создаёт поле field для каждого столбца, определенного в файле schema.yml. Под ключом fields вы можете изменить представление каждого поля. Например, настройки полей в Примере 14-7 определяют текст подписи поля, тип поля для ввода, класс css для вывода поля и подсказку для полей title и content. В следующих разделах будет детально описано, как работает каждый параметр.

Пример 14-7 - Настройка различных меток для полей ввода-вывода

generator:
  class:              sfPropelAdminGenerator
  param:
    model_class:      Article
    theme:            default

    fields:
      title:          { name: Article Title, type: textarea_tag, params: class=foo }
      content:        { name: Body, help: Fill in the article body }

В дополнение к типовой конфигурации для всех представлений, вы можете переопределить настройки полей для каждого представления (list и edit), как показано в Примере 14-8.

Пример 14-8 - Переопределение настроек для каждого представления - Overriding Global Settings View per View

generator:
  class:              sfPropelAdminGenerator
  param:
    model_class:      Article
    theme:            default

    fields:
      title:          { name: Article Title }
      content:        { name: Body }

    list:
      fields:
        title:        { name: Title }

    edit:
      fields:
        content:      { name: Body of the article }

Это общий принцип: любые настройки, установленные для всего модуля под ключом fields могут быть переопределены для конкретных представлений.

Добавление полей в представление - Adding Fields to the Display

Поля, которые вы определяете в секции fields, могут быть показаны, скрыты, отсортированы и сгруппированы различными способами для каждого представления. Для этого используется ключ display. Например, что бы расставить поля модуля comment, используйте код Примера 14-9.

Пример 14-9 - Choosing the Fields to Display, in modules/comment/config/generator.yml

generator:
  class:              sfPropelAdminGenerator
  param:
    model_class:      Comment
    theme:            default

    fields:
      article_id:     { name: Article }
      created_at:     { name: Published on }
      content:        { name: Body }

    list:
      display:        [id, article_id, content]

    edit:
      display:
        NONE:         [article_id]
        Editable:     [author, content, created_at]

Представление list будет показывать три столбца, как на рисунке 14-8, а представление edit будет показывать четыре поля, собранных в две группы, как показано на Рисунке 14-9.

Рисунок 14-8 - Custom column setting in the list view of the comment module

Custom column setting in the list view of the comment module

Рисунок 14-9 - Grouping fields in the edit view of the comment module

Grouping fields in the edit view of the comment module

Так что вы можете использовать настройки display двумя способами:

  • Что бы указать, какие столбцы(поля) показывать и в каком порядке, внесите поля в простой массив, как показано в предыдущем представлении list.
  • Что бы сгрупировать поля, используйте ассоциативный массив с именем группы в качестве ключа, или NONE, что бы сформировать группу без имени. Значением по-прежнему будет упорядоченный список имён полей.

TIP По умолчанию, первичный ключ никогда не отображается ни в каком представлении.

Custom Fields

Вообще-то, поля в generator.yml не обязательно должны соответствовать полям, определенным в схеме. Если соответствующий класс предоставляет геттер, он может быть использован в представлении list; если есть геттер и/или сеттер, он может быть использован в представлении edit. Например, вы можете расширить модель Article, добавив метод getNbComments(), как показано в Примере 14-10.

Пример 14-10 – Добавление собственного геттера в модель, lib/model/Article.class.php

[php]
public function getNbComments()
{
  return $this->countComments();
}

Теперь nb_comments доступна как поле в генерируемом модуле (заметьте, что геттер использует camelCase-соглашение для имени поля).

Пример 14-11 - Custom Getters Provide Additional Columns for Administration Modules, in backend/modules/article/config/generator.yml

generator:
  class:              sfPropelAdminGenerator
  param:
    model_class:      Article
    theme:            default

    list:
      display:        [id, title, nb_comments, created_at]

The resulting list view of the article module is shown in Figure 14-10.

Рисунок 14-10 - Custom field in the list view of the article module

Custom field in the list view of the article module

Custom fields can even return HTML code to display more than raw data. For instance, you can extend the Comment class with a getArticleLink() method as in Listing 14-12.

Пример 14-12 - Adding a Custom Getter Returning HTML, in lib/model/Comment.class.php

[php]
public function getArticleLink()
{
  return link_to($this->getArticle()->getTitle(), 'article/edit?id='.$this->getArticleId());
}

You can use this new getter as a custom field in the comment/list view with the same syntax as in Listing 14-11. See the example in Listing 14-13, and the result in Figure 14-11, where the HTML code output by the getter (a hyperlink to the article) appears in the second column instead of the article primary key.

Пример 14-13 - Custom Getters Returning HTML Can Also Be Used As Additional Columns, in modules/comment/config/generator.yml

generator:
  class:              sfPropelAdminGenerator
  param:
    model_class:      Comment
    theme:            default

    list:
      display:        [id, article_link, content]

Рисунок 14-11 - Custom field in the list view of the comment module

Custom field in the list view of the comment module

Partial Fields

Код модели должен быть независимым от представления. Приведенный пример метода getArticleLink() нарушает этот принцип, потому что кусочек кода представления появился в коде модели. Что бы достичь требуемого эффекта корректным путем, вам лучше разместить код, который выводит HTML для заказного поля, в обособленном фрагменте шаблона. К счастью, генератор админок позволяет вам объявить поле, название которого начинается со знака подчеркивания. В таком случае, файл generator.yml из Примера 14-13 будет изменен таким образом, как показано в Примере 14-14.

Пример 14-14 - Обособленные фрагменты шаблона могут использоваться как дополнительные поля с помощью префикса _

    list:
      display:        [id, _article_link, created_at]

Что бы это работало, обособленный фрагмент шаблона с названием _article_link.php, код которого показан в Примере 14-15, должен быть создан в каталоге modules/comment/templates/.

Пример 14-15 - Обособленный фрагмент шаблона для представления list, в файле modules/comment/templates/_article_link.php

<?php echo link_to($comment->getArticle()->getTitle(), 'article/edit?id='.$comment->getArticleId()) ?>

Notice that the partial template of a partial field has access to the current object through a variable named by the class ($comment in this example). For instance, for a module built for a class called UserGroup, the partial will have access to the current object through the $user_group variable.

The result is the same as in Figure 14-11, except that the layer separation is respected. If you get used to respecting the layer separation, you will end up with more maintainable applications.

If you need to customize the parameters of a partial field, do the same as for a normal field, under the field key. Just don't include the leading underscore (_) in the key--see an example in Listing 14-16.

Пример 14-16 - Partial Field Properties Can Be Customized Under the fields Key

      fields:
        article_link:   { name: Article }

If your partial becomes crowded with logic, you'll probably want to replace it with a component. Change the _ prefix to ~ and you can define a component field, as you can see in Listing 14-17.

Пример 14-17 - Components Can Be Used As Additional Columns--Use the ~ Prefix

    ...
    list:
      display:        [id, ~article_link, created_at]

In the generated template, this will result by a call to the articleLink component of the current module.

NOTE Custom and partial fields can be used in the list view, the edit view, and for filters. If you use the same partial for several views, the context ('list', 'edit', or 'filter') is stored in the $type variable.

View Customization

To change the edit and list views' appearance, you could be tempted to alter the templates. But because they are automatically generated, doing so isn't a very good idea. Instead, you should use the generator.yml configuration file, because it can do almost everything that you need without sacrificing modularity.

Изменение заглавия представления

In addition to a custom set of fields, the list and edit pages can have a custom page title. For instance, if you want to customize the title of the article views, do as in Listing 14-18. The resulting edit view is illustrated in Figure 14-12.

Пример 14-18 - Setting a Custom Title for Each View, in backend/modules/article/config/generator.yml

    list:
      title:          List of Articles
      ...

    edit:
      title:          Body of article %%title%%
      display:        [content]

Рисунок 14-12 - Custom title in the edit view of the article module

Custom title in the edit view of the article module

As the default titles use the class name, they are often good enough--provided that your model uses explicit class names.

TIP In the string values of generator.yml, the value of a field can be accessed via the name of the field surrounded by %%.

Adding Tooltips

In the list and edit views, you can add tooltips to help describe the fields that are displayed. For instance, to add a tooltip to the article_id field of the edit view of the comment module, add a help property in the fields definition as in Listing 14-19. The result is shown in Figure 14-13.

Пример 14-19 - Setting a Tooltip in the edit View, in modules/comment/config/generator.yml

    edit:
      fields:
        ...
        article_id:   { help: The current comment relates to this article }

Рисунок 14-13 - Tooltip in the edit view of the comment module

Tooltip in the edit view of the comment module

In the list view, tooltips are displayed in the column header; in the edit view, they appear under the input.

Modifying the Date Format

Dates can be displayed using a custom format as soon as you use the date_format param, as demonstrated in Listing 14-20.

Пример 14-20 - Formatting a Date in the list View

    list:
      fields:
        created_at:         { name: Published, params: date_format='dd/MM' }

It takes the same format parameter as the format_date() helper described in the previous chapter.

SIDEBAR Administration templates are i18N ready

All of the text found in the generated templates is automatically internationalized (i.e., enclosed in a call to the __() helper). This means that you can easily translate a generated administration by adding the translations of the phrases in an XLIFF file, in your apps/myapp/i18n/ directory, as explained in the previous chapter.

List View-Specific Customization

The list view can display the details of a record in a tabular way, or with all the details stacked in one line. It also contains filters, pagination, and sorting features. These features can be altered by configuration, as described in the next sections.

Изменение обрамления

By default, the hyperlink between the list view and the edit view is borne by the primary key column. If you refer back to Figure 14-11, you will see that the id column in the comment list not only shows the primary key of each comment, but also provides a hyperlink allowing users to access the edit view.

If you prefer the hyperlink to the detail of the record to appear on another column, prefix the column name by an equal sign (=) in the display key. Listing 14-21 shows how to remove the id from the displayed fields of the comment list and to put the hyperlink on the content field instead. Check Figure 14-14 for a screenshot.

Пример 14-21 - Moving the Hyperlink for the edit View in the list View, in modules/comment/config/generator.yml

    list:
      display:    [article_link, =content]

Рисунок 14-14 - Moving the link to the edit view on another column, in the list view of the comment module

Moving the link to the edit view on another column, in the list view of the comment module

By default, the list view uses the tabular layout, where the fields appear as columns, as shown previously. But you can also use the stacked layout and concatenate the fields into a single string that expands on the full length of the table. If you choose the stacked layout, you must set in the params key the pattern defining the value of each line of the list. For instance, Listing 14-22 defines a stacked layout for the list view of the comment module. The result appears in Figure 14-15.

Пример 14-22 - Using a stacked Layout in the list View, in modules/comment/config/generator.yml

    list:
      layout:  stacked
      params:  |
        %%=content%% <br />
        (sent by %%author%% on %%created_at%% about %%article_link%%)
      display:  [created_at, author, content]

Рисунок 14-15 - Stacked layout in the list view of the comment module

Stacked layout in the list view of the comment module

Notice that a tabular layout expects an array of fields under the display key, but a stacked layout uses the params key for the HTML code generated for each record. However, the display array is still used in a stacked layout to determine which column headers are available for the interactive sorting.

Filtering the Results

In a list view, you can add a set of filter interactions. With these filters, users can both display fewer results and get to the ones they want faster. Configure the filters under the filters key, with an array of field names. For instance, add a filter on the article_id, author, and created_at fields to the comment list view, as in Listing 14-23, to display a filter box similar to the one in Figure 14-16. You will need to add a __toString() method to the Article class (returning, for instance, the article title) for this to work.

Пример 14-23 - Setting the Filters in the list View, in modules/comment/config/generator.yml

    list:
      filters: [article_id, author, created_at]
      layout:  stacked
      params:  |
        %%=content%% <br />
        (sent by %%author%% on %%created_at%% about %%article_link%%)
      display:  [created_at, author, content]

Рисунок 14-16 - Filters in the list view of the comment module

Filters in the list view of the comment module

The filters displayed by symfony depend on the column type:

  • For text columns (like the author field in the comment module), the filter is a text input allowing text-based search with wildcards (*).
  • For foreign keys (like the article_id field in the comment module), the filter is a drop-down list of the records of the related table. As for the regular object_select_tag(), the options of the drop-down list are the ones returned by the __toString() method of the related class.
  • For date columns (like the created_at field in the comment module), the filter is a pair of rich date tags (text fields filled by calendar widgets), allowing the selection of a time interval.
  • For Boolean columns, the filter is a drop-down list having true, false, and true or false options--the last value reinitializes the filter.

Just like you use partial fields in lists, you can also use partial filters to create a filter that symfony doesn't handle on its own. For instance, imagine a state field that may contain only two values (open and closed), but for some reason you store those values directly in the field instead of using a table relation. A simple filter on this field (of type string) would be a text-based search, but what you want is probably a drop-down list of values. That's easy to achieve with a partial filter. See Listing 14-24 for an example implementation.

Пример 14-24 - Using a Partial Filter

[php]
// Define the partial, in templates/_state.php
<?php echo select_tag('filters[state]', options_for_select(array(
  '' => '',
  'open' => 'open',
  'closed' => 'closed',
), isset($filters['state']) ? $filters['state'] : '')) ?>

// Add the partial filter in the filter list, in config/generator.yml
    list:
      filters:        [date, _state]

Notice that the partial has access to a $filters variable, which is useful to get the current value of the filter.

There is one last option that can be very useful for looking for empty values. Imagine that you want to filter the list of comments to display only the ones that have no author. The problem is that if you leave the author filter empty, it will be ignored. The solution is to set the filter_is_empty field setting to true, as in Listing 14-25, and the filter will display an additional check box, which will allow you to look for empty values, as illustrated in Figure 14-17.

Пример 14-25 - Adding Filtering of Empty Values on the author Field in the list View

    list:
      fields:
        author:   { filter_is_empty: true }
      filters:    [article_id, author, created_at]

Рисунок 14-17 - Allowing the filtering of empty author values

Allowing the filtering of empty author values

Сортировка списка

В представлении list, заголовки таблиц - это ссылки, которые можно использовать для сортировки списка, как показано на рисунке 14-18. Эти заголовки показываются и в табличной, и в stacked верстке. При нажатии этих ссылок, таблица загружается с параметром sort, что соотвествующим образом меняет очередность расположения данных в списке.

Рисунок 14-18 - Заголовки столбцов таблицы в представлении list в качестве средств управления сортировкой

Table headers of the list view are sort controls

Вы можете повторно использовать синтаксис URI, что бы получить список, отсортированный нужным образом:

[php]
<?php echo link_to('Comment list by date', 'comment/list?sort=created_at&type=desc' ) ?>

Вы так же можете определить порядок сортировки по умолчанию в файле generator.yml. Синтаксис приведен в Примере 14-26.

Пример 14-26 - Настройка сортировки по умолчанию для представления list

    list:
      sort:   created_at
      # Альтернативный синтаксис, что бы указать направление сортировки - Alternative syntax, to specify a sort order
      sort:   [created_at, desc]

NOTE Только поля, соответствующие реальным столбцам БД, могут быть преобразованы в элементы, управляющие сортировкой--но не заказные поля или поля, формируемые обособленным фрагментом шаблона.

Управление постраничной разбивкой

Сгенерированная админка эффективно работает даже с большими таблицами, потому что представление list изначально использует постраничную разбивку. Когда количество записей в таблице превышает максимально допустимое количество строк на странице, внизу списка появляются элементы навигации между страницами. Например, рисунок 14-19 показывает список из шести комментариев в таблице с лимитом пять комментариев для одной страницы. Постраничная разбивка обеспечивает хорошую производительность, потому что из БД извлекаются только те записи, которые отображаются. Таким образом, админка может обеспечить работу с таблицами, содержащими миллионы записей.

Рисунок 14-19 - В длинных списках появляются элементы навигации между страницами

В длинных списках появляются элементы навигации между страницами

Вы можете настроить количество записей, отображаемое на одной странице, при помощи параметра max_per_page:

    list:
      max_per_page:   5

Using a Join to Speed Up Page Delivery

По умолчанию, генератор админок использует простой doSelect() для получения списка записей. Но, если вы используете в списке связанные между собой объекты, количество запросов, требуемых для отображения списка, может резко увеличиться. Например, если вы желаете показать названия статей в списке комментариев, для каждого комментария потребуется отдельный запрос на получение соответствующего объекта Article. В этом случае, вы, возможно, предпочтете использовать запрос вида doSelectJoinXXX(), что бы уменьшить число запросов к БД. Это можно сделать, указав параметр peer_method:

    list:
      peer_method:   doSelectJoinArticle

Глава 18 исчерпывающе объяснит концепцию объединений таблиц (Join). >NOTE >Я не уверен, что при использовании mysql объединения улучшат производительность. (Прим. перев.)

Edit View-Specific Customization

В представлении edit, пользователь может модифицировать все поля выбранной записи. Симфони определяет, какого типа должен быть элемент, предназначенный для редактирования поля, основываясь на типе данных соответствующего столбца. Затем она генерирует помощник object_*_tag(), and passes that helper the object and the property to edit. Например, если конфигурация представления edit оговаривает, что пользователь может редактировать поле title:

    edit:
      display: [title, ...]

то страница edit для редактирования title покажет поле для ввода текста, потому что это поле определено в схеме как varchar.

[php]
<?php echo object_input_tag($article, 'getTitle') ?>

Изменение тега Changing the Input Type

The default type-to-field conversion rules are as follows:

  • A column defined as integer, float, char, varchar(size) appears in the edit view as an object_input_tag().
  • A column defined as longvarchar appears as an object_textarea_tag().
  • A foreign key column appears as an object_select_tag().
  • A column defined as boolean appears as an object_checkbox_tag().
  • A column defined as a timestamp or date appears as an object_input_date_tag().

You may want to override these rules to specify a custom input type for a given field. To that extent, set the type parameter in the fields definition to a specific form helper name. As for the options of the generated object_*_tag(), you can change them with the params parameter. See an example in Listing 14-27.

Пример 14-27 - Setting a Custom Input Type and Params for the edit View

generator:
  class:              sfPropelAdminGenerator
  param:
    model_class:      Comment
    theme:            default

    edit:
      fields:
                      ## Drop the input, just display plain text
        id:           { type: plain }
                      ## The input is not editable
        author:       { params: disabled=true }
                      ## The input is a textarea (object_textarea_tag)
        content:      { type: textarea_tag, params: rich=true css=user.css tinymce_options=width:330 }
                      ## The input is a select (object_select_tag)
        article_id:   { params: include_custom=Choose an article }
         ...

The params parameters are passed as options to the generated object_*_tag(). For instance, the params definition for the preceding article_id will produce in the template the following:

<?php echo object_select_tag($comment, 'getArticleId', 'related_class=Article', 'include_custom=Choose an article') ?>

This means that all the options usually available in the form helpers can be customized in an edit view.

Handling Partial Fields

Partial fields can be used in edit views just like in list views. The difference is that you have to handle by hand, in the action, the update of the column according to the value of the request parameter sent by the partial field. Symfony knows how to handle the normal fields (corresponding to actual columns), but can't guess how to handle the inputs you may include in partial fields.

For instance, imagine an administration module for a User class where the available fields are id, nickname, and password. The site administrator must be able to change the password of a user upon request, but the edit view must not display the value of the password field for security reasons. Instead, the form should display an empty password input that the site administrator can fill to change the value. The generator settings for such an edit view are then similar to Listing 14-28.

Пример 14-28 - Including a Partial Field in the edit View

    edit:
      display:        [id, nickname, _newpassword]
      fields:
        newpassword:  { name: Password, help: Enter a password to change it, leave the field blank to keep the current one }

The templates/_newpassword.php partial contains something like this:

[php]
<?php echo input_password_tag('newpassword', '') ?>

Notice that this partial uses a simple form helper, not an object form helper, since it is not desirable to retrieve the password value from the current User object to populate the form input--which could disclose the user password.

Now, in order to use the value from this control to update the object in the action, you need to extend the updateUserFromRequest() method in the action. To do that, create a method with the same name in the action class file with the custom behavior for the input of the partial field, as in Listing 14-29.

Пример 14-29 - Handling a Partial Field in the Action, in modules/user/actions/actions.class.php

[php]
class userActions extends sfActions
{
  protected function updateUserFromRequest()
  {
    // Handle the input of the partial field
    $password = $this->getRequestParameter('newpassword');

    if ($password)
    {
      $this->user->setPassword($password);
    }

    // Let symfony handle the other fields
    parent::updateUserFromRequest();
  }
}

NOTE In the real world, a user/edit view usually contains two password fields, the second having to match the first one to avoid typing mistakes. In practice, as you saw in Chapter 10, this is done via a validator. The administration-generated modules benefit from this mechanism just like regular modules.

Dealing with Foreign Keys

Если ваша схема определяет связи между таблицами, the generated administration modules take advantage of it and offer even more automated controls, thus greatly simplifying the relationship management.

One-to-Many Relationships

The 1-n table relationships are taken care of by the administration generator. As is depicted by Figure 14-1 earlier, the blog_comment table is related to the blog_article table through the article_id field. If you initiate the module of the Comment class with the administration generator, the comment/edit action will automatically display the article_id as a drop-down list showing the IDs of the available records of the blog_article table (check again Figure 14-9 for an illustration).

In addition, if you define a __toString() method in the Article object, the text of the drop-down options use it instead of the primary keys.

If you need to display the list of comments related to an article in the article module (n-1 relationship), you will need to customize the module a little by way of a partial field.

Many-to-Many Relationships

Symfony also takes care of n-n table relationships, but since you can't define them in the schema, you need to add a few parameters to the generator.yml file.

Реализация отношений "многие-ко-многим" требует промежуточной таблицы. Например, если между таблицами blog_article и blog_author существует отношение "многие-ко-многим" (статья может быть написана несколькими авторами и автор может участвовать в написании нескольких статей), ваша база данных будет содержать таблицу blog_article_author, или ей подобную, как показано на Рисунке 14-20.

Рисунок 14-20 - Using a "through class" to implement many-to-many relationships

Using a "through class" to implement many-to-many relationships

При этом, модель будет содержать класс ArticleAuthor, и это всё, что нужно генератору админок, но вы должны передать его как параметр through_class.

Например, в генерируемом модуле, основанном на классе Article, вы можете добавить поле, предназначенное для создания новых связей "многие-ко-многим" с классом Author, если вы опишите его в файле generator.yml так, как показано в Примере 14-30.

Пример 14-30 - Поддержка отношения многие-ко-многим при помощи параметра through_class

    edit:
      fields:
        article_author: { type: admin_double_list, params: through_class=ArticleAuthor }

Such a field handles links between existing objects, so a regular drop-down list is not enough. You must use a special type of input for that. Symfony offers three widgets to help relate members of two lists (illustrated in Figure 14-21):

  • An admin_double_list is a set of two expanded select controls, together with buttons to switch elements from the first list (available elements) to the second (selected elements).
  • An admin_select_list is an expanded select control in which you can select many elements.
  • An admin_check_list is a list of check box tags.

Рисунок 14-21 - Available controls for many-to-many relationships

Available controls for many-to-many relationships

Adding Interactions

Administration modules allow users to perform the usual CRUD operations, but you can also add your own interactions or restrict the possible interactions for a view. For instance, the interaction definition shown in Listing 14-31 gives access to all the default CRUD actions on the article module.

Пример 14-31 - Defining Interactions for Each View, in backend/modules/article/config/generator.yml

    list:
      title:          List of Articles
      object_actions:
        _edit:         ~
        _delete:       ~
      actions:
        _create:       ~

    edit:
      title:          Body of article %%title%%
      actions:
        _list:         ~
        _save:         ~
        _save_and_add: ~
        _delete:       ~

In a list view, there are two action settings: the list of actions available for every object, and the list of actions available for the whole page. The list interactions defined in Listing 14-31 render like in Figure 14-22. Each line shows one button to edit the record and one to delete it. At the bottom of the list, a button allows the creation of a new record.

Рисунок 14-22 - Interactions in the list view

Interactions in the list view

In an edit view, as there is only one record edited at a time, there is only one set of actions to define. The edit interactions defined in Listing 14-31 render like in Figure 14-23. Both the save and the save_and_add actions save the current edits in the records, the difference being that the save action displays the edit view on the current record after saving, while the save_and_add action displays an empty edit view to add another record. The save_and_add action is a shortcut that you will find very useful when adding many records in rapid succession. As for the position of the delete action, it is separated from the other buttons so that users don't click it by mistake.

The interaction names starting with an underscore (_) tell symfony to use the default icon and action corresponding to these interactions. The administration generator understands _edit, _delete, _create, _list, _save, _save_and_add, and _create.

Рисунок 14-23 - Interactions in the edit view

Interactions in the edit view

But you can also add a custom interaction, in which case you must specify a name starting with no underscore, as in Listing 14-32.

Пример 14-32 - Defining a Custom Interaction

    list:
      title:          List of Articles
      object_actions:
        _edit:        -
        _delete:      -
        addcomment:   { name: Add a comment, action: addComment, icon: backend/addcomment.png }

Each article in the list will now show the addcomment.png button, as shown in Figure 14-24. Clicking it triggers a call to the addComment action in the current module. The primary key of the current object is automatically added to the request parameters.

Рисунок 14-24 - Custom interaction in the list view

Custom interaction in the list view

The addComment action can be implemented as in Listing 14-33.

Пример 14-33 - Implementing the Custom Interaction Action, in actions/actions.class.php

[php]
public function executeAddComment()
{
  $comment = new Comment();
  $comment->setArticleId($this->getRequestParameter('id'));
  $comment->save();

  $this->redirect('comment/edit?id='.$comment->getId());
}

One last word about actions: If you want to suppress completely the actions for one category, use an empty list, as in Listing 14-34.

Пример 14-34 - Removing All Actions in the list View

    list:
      title:          List of Articles
      actions:        {}

Проверка данных, передаваемых через формы

Если вы посмотрите на сгенерированный шаблон _edit_form.php в каталоге cache/ вашего проекта, вы увидите, что поля форм используют специальное соглашение о наименовании. В генерируемом представлении edit, имена полей ввода являются результатом соединения имени-с-подчеркиваниями класса модели и имени поля в квадратных скобках. If you take a look at the generated _edit_form.php template in your project cache/ directory, you will see that the form fields use a special naming convention. In a generated edit view, the input names result from the concatenation of the underscore-syntaxed model class name and the field name between angle brackets.

Например, если представление edit класса Article содержит поле title, поле будет обозначено как article[title].

Пример 14-35 - Синтаксис генерируемых имен полей ввода

// generator.yml
generator:
  class:              sfPropelAdminGenerator
  param:
    model_class:      Article
    theme:            default
    edit:
      display: [title]

// Resulting _edit_form.php template
<?php echo object_input_tag($article, 'getTitle', array('control_name' => 'article[title]')) ?>

// Resulting HTML
<input type="text" name="article[title]" id="article[title]" value="My Title" />

This has plenty of advantages during the internal form-handling process. However, as explained in Chapter 10, it makes the form validation configuration a bit trickier, so you have to change square brackets, [ ], to curly braces, { }, in the fields definition. Also, when using a field name as a parameter for a validator, you should use the name as it appears in the generated HTML code (that is, with the square brackets, but between quotes). Refer to Listing 14-36 for a detail of the special validator syntax for generated forms.

Пример 14-36 - Синаксис файла валидации для генерируемых форм админок

## В списке полей, замените квадратные скобки круглыми
  article{title}:
    required:
      msg: You must provide a title
    ## Для параметров валидатора используйте название поля, заключенное в кавычки
    sfCompareValidator:
      check:        "user[newpassword]"
      compare_error: The password confirmation does not match the password.

Restricting User Actions Using Credentials

For a given administration module, the available fields and interactions can vary according to the credentials of the logged user (refer to Chapter 6 for a description of symfony's security features).

The fields in the generator can take a credentials parameter into account so as to appear only to users who have the proper credential. This works for the list view and the edit view. Additionally, the generator can also hide interactions according to credentials. Listing 14-37 demonstrates these features.

Пример 14-37 - Using Credentials in generator.yml

## The id column is displayed only for users with the admin credential
    list:
      title:          List of Articles
      layout:         tabular
      display:        [id, =title, content, nb_comments]
      fields:
        id:           { credentials: [admin] }

## The addcomment interaction is restricted to the users with the admin credential
    list:
      title:          List of Articles
      object_actions:
        _edit:        -
        _delete:      -
        addcomment:   { credentials: [admin], name: Add a comment, action: addComment, icon: backend/addcomment.png }

Изменение представления генерируемых модулей

You can modify the presentation of the generated modules so that it matches any existing graphical charter, not only by applying your own style sheet, but also by overriding the default templates.

Использование своей таблицы стилей

Since the generated HTML is structured content, you can do pretty much anything you like with the presentation.

You can define an alternative CSS to be used for an administration module instead of a default one by adding a css parameter to the generator configuration, as in Listing 14-38.

Пример 14-38 - Using a Custom Style Sheet Instead of the Default One

generator:
  class:              sfPropelAdminGenerator
  param:
    model_class:      Comment
    theme:            default
    css:              mystylesheet

Alternatively, you can also use the mechanisms provided by the module view.yml to override the styles on a per-view basis.

Creating a Custom Header and Footer

The list and edit views systematically include a header and footer partial. There is no such partial by default in the templates/ directory of an administration module, but you just need to add one with one of the following names to have it included automatically:

_list_header.php
_list_footer.php
_edit_header.php
_edit_footer.php

For instance, if you want to add a custom header to the article/edit view, create a file called _edit_header.php as in Listing 14-39. It will work with no further configuration.

Пример 14-39 - Example edit Header Partial, in modules/articles/template/_edit_header.php

[php]
<?php if ($article->getNbComments() > 0): ?>
  <h2>This article has <?php echo $article->getNbComments() ?> comments.</h2>
<?php endif; ?>

Notice that an edit partial always has access to the current object through a variable named after the class, and that a list partial always has access to the current pager through the $pager variable.

SIDEBAR Calling the Administration Actions with Custom Parameters

The administration module actions can receive custom parameters using the query_string argument in a link_to() helper. For example, to extend the previous _edit_header partial with a link to the comments for the article, write this:

[php]
<?php if ($article->getNbComments() > 0): ?>
  <h2>This article has <?php echo link_to($article->getNbComments().' comments', 'comment/list', array('query_string' => 'filter=filter&filters%5Barticle_id%5D='.$article->getId())) ?></h2>
<?php endif; ?>

This query string parameter is an encoded version of the more legible

'filter=filter&filters[article_id]='.$article->getId()

It filters the comments to display only the ones related to $article. Using the query_string argument, you can specify a sorting order and/or a filter to display a custom list view. This can also be useful for custom interactions.

Customizing the Theme

Что бы удовлетворить ваши требования, в папке templates/ модуля можно переопределить другие обособленные фрагменты шаблонов, унаследованные от фреймворка.

Сгенерированные шаблоны разбиты на маленькие кусочки, которые могут быть переопределены независимо друг от друга, и действия так же могут быть изменены одно за другим.

Однако, если вы хотите переопределить их для нескольких модулей одинаковым способом, возможно, вам следует создать повторно используемую тему. Тема - это набор шаблонов и действий, которые могут быть использованы в модуле админки при помощи указания значения theme в начале файла generator.yml. С темой по умолчанию, симфони использует файлы, находящиеся в каталоге $sf_symfony_data_dir/generator/sfPropelAdmin/default/.

Файлы темы должны быть расположены внутри проекта, в каталоге data/generator/sfPropelAdmin/[theme_name]/template/, и вы можете начать создание новой темы, скопировав файлы из темы по умолчанию. Таким образом, вы можете быть уверены, что все файлы, необходимые для темы, будут присутствовать в вашей теме.

// Обособленные фрагменты шаблонов, в [theme_name]/template/templates/
_edit_actions.php
_edit_footer.php
_edit_form.php
_edit_header.php
_edit_messages.php
_filters.php
_list.php
_list_actions.php
_list_footer.php
_list_header.php
_list_messages.php
_list_td_actions.php
_list_td_stacked.php
_list_td_tabular.php
_list_th_stacked.php
_list_th_tabular.php

// Действия, в [theme_name]/template/actions/actions.class.php
processFilters()     // Обработка фильтров запроса
addFiltersCriteria() // Добавляет фильтр к объекту `Criteria`
processSort()
addSortCriteria()

Обратите внимание на то, что файлы шаблонов - это фактически шаблоны шаблонов, то есть, PHP-файлы, которые будут обработаны специальной утилитой, что бы сгенерировать шаблоны, основанные на настройках генератора (это называется фазой компиляции). Сгенерированные шаблоны по-прежнему должны содержать PHP-код, который выполняется при веб-серфинге, так что шаблоны шаблонов используют альтернативный синтаксис, что бы PHP-код не был выполнен при первом проходе. Пример 14-40 показывает содержимое типичного шаблона шаблонов.

Пример 14-40 - Синтаксис шаблона шаблонов

[php]
<?php foreach ($this->getPrimaryKey() as $pk): ?>
[?php echo object_input_hidden_tag($<?php echo $this->getSingularName() ?>,'get<?php echo $pk->getPhpName() ?>') ?]
<?php endforeach; ?>

В этом примере, код, начинающийся с <? исполняется на этапе компиляции, а код, начинающийся с [?, выполняется при обращении к странице, а движок шаблонов преобразует теги [? в <?, так что окончательный шаблон будет выглядеть так:

[php]
<?php echo object_input_hidden_tag($article, 'getId') ?>

Dealing with templates of templates is tricky, so the best advice if you want to create your own theme is to start from the default theme, modify it step by step, and test it extensively.

TIP Вы так же можете запаковать тему для генератора в плагин, после чего её можно легко внедрять в различные приложения. (См. Главу 17.)

-

SIDEBAR Создание собственного генератора

Генераторы каркасов и админок используют набор внутренних компонентов симфони, которые автоматизируют создание действий и шаблонов, использование тем, обработку шаблонов шаблонов.themes, and the parsing of templates of templates.

This means that symfony provides all the tools to build your own generator, which can look like the existing ones or be completely different. The generation of a module is managed by the generate() method of the sfGeneratorManager class. For instance, to generate an administration, symfony calls the following internally:

[php]
$generator_manager = new sfGeneratorManager();
$data = $generator_manager->generate('sfPropelAdminGenerator', $parameters);

If you want to build your own generator, you should look at the API documentation of the sfGeneratorManager and the sfGenerator classes, and take as examples the sfAdminGenerator and sfCRUDGenerator classes.

Summary

Основой каркасов ваших модулей и автоматически генерируемых приложений является хорошо продуманная схема данных и объектная модель. Вы можете модифицировать PHP-код каркасов, а генерируемые модули изменяются, в основном, через изменения в конфигурации.

The generator.yml file is the heart of the programming of generated back-ends. It allows for the complete customization of content, features, and the look and feel of the list and edit views. You can manage field labels, tooltips, filters, sort order, page size, input type, foreign relationships, custom interactions, and credentials directly in YAML, without a single line of PHP code.

If the administration generator doesn't natively support the feature you need, the partial fields and the ability to override actions provide complete extensibility. Plus, you can reuse your adaptations to the administration generator mechanisms thanks to the theme mechanisms.