developer.co.ua

Holy Copypasters
22.06.2007
Алексей Гоголев

Глава 4. Основы cоздания cтранички 0.26

Первый туториал, который проходят программисты, изучая новый язык или фреймворк, состоит в том, чтобы вывести на экран фразу “Hello, world!”. Странно считать, что компьютер может приветствовать мир, учитывая то, что сейчас искусственный интеллект демонстрирует достаточно бедные разговорные возможности. Но symfony ни чем не хуже, и доказательством послужит страничка с текстом: Hello, <ваше имя здесь>.

Эта глава расскажет как создать модуль (module) — структурный элемент, содержащий группу страничек, как создать страничку, которая согласно MVC pattern разделена на действие (action) и шаблон (template). Будет рассмотрено, как создавать и обрабатывать ссылки и формы (form) — базовые элементы для взаимодействия с пользователем.

Создание Модуля


Как объяснялось в Главе 2, symfony группирует странички в модули. Прежде чем создать страничку необходимо создать модуль. Модуль сначала являет собой пустую оболочку, файловую структуру, которую symfony может распознать.

Команды консоли symfony автоматизируют создание модуля. Вам нужно просто вызвать команду init-module с именем приложения (application) и именем модуля (module) в качестве параметров. В предыдущей главе, было создано приложение myapp. Для того чтобы создать модуль mymodule в этом приложении, наберите следующую команду:
> cd ~/myproject
> symfony init-module myapp mymodule

>> dir+      ~/myproject/apps/myapp/modules/mymodule
>> dir+      ~/myproject/apps/myapp/modules/mymodule/actions
>> file+     ~/myproject/apps/myapp/modules/mymodule/actions/actions.class.php
>> dir+      ~/myproject/apps/myapp/modules/mymodule/config
>> dir+      ~/myproject/apps/myapp/modules/mymodule/lib
>> dir+      ~/myproject/apps/myapp/modules/mymodule/templates
>> file+     ~/myproject/apps/myapp/modules/mymodule/templates/indexSuccess.php
>> dir+      ~/myproject/apps/myapp/modules/mymodule/validate
>> file+     ~/myproject/test/functional/myapp/mymoduleActionsTest.php
>> tokens    ~/myproject/test/functional/myapp/mymoduleActionsTest.php
>> tokens    ~/myproject/apps/myapp/modules/mymodule/actions/actions.class.php
>> tokens    ~/myproject/apps/myapp/modules/mymodule/templates/indexSuccess.php

Кроме директорий actions/, config/, lib/, templates/, и validate/, эта команда создает еще три файла. Первый — в папке test/, связан с юнит тестами, и вам он не понадобится до Главы 15. Файл actions.class.php (см. Листинг 4–1) переадресовывает на поздравительную страницу. И пустой файл templates/indexSuccess.php.


Листинг 4–1 – Сгенерированное Действие (action) в actions/actions.class.php
<?php
 
class mymoduleActions extends sfActions
{
  public function 
executeIndex()
  {
    
$this->forward('default''module');
  }
}


Если вы взгляните на реально действующий файл actions.class.php, вы увидите гораздо больше строк кода и множество комментариев. Symfony рекомендует сопровождать каждый класс комментариями, совместимыми с phpDocumentor (http://www.phpdoc.org/), чтобы в дальнейшем создать документацию для проекта.


Для каждого нового модуля symfony по умолчанию создает действие index. Сначала выполняется метод executeIndex, после чего вызывается шаблон indexSuccess.php. Смысл префикса execute и суффикса Success объясняется в Главах 6 и 7. Тем временем, будем воспринимать такую схему наименования просто как правило (convention). Вы можете увидеть соответствующую страничку (см. Рисунок 4–1) запросив следующий URL:

http://localhost/myapp_dev.php/mymodule/index


Действие (action) index не будет использоваться в этой главе, так что можно удалить метод executeIndex() из файла actions.class.php и удалить соответствующий шаблон indexSuccess.php из директории templates/.

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


Рисунок 4–1 – Генерируемая по Умолчанию Главная Страница (index page)
http://developer.co.ua/upload/Image/sf_book/F0401.jpg

Создание Странички


В symfony, логика станицы хранится в действии (action), и представление данных (presentation) осуществляется в шаблоне. Для страничек без логики нужно создать пустое действие.

Создание Действия


Страничка “Hello, world!” будет доступна через действие myAction. чтобы создать это действие, просто добавьте метод executeMyAction в класс mymoduleActions, как показано в листинге 4–2.

Листинг 4–2 – Добавить Действие (Action) Означает Добавить Метод в Класс Содержащий Действия.
<?php
 
class mymoduleActions extends sfActions
{
  public function 
executeMyAction()
  {
  }
}


Имя метода должно выгладить как execute``Xxx``(). Вторая часть имени метода это имя действия (action), написанное с большой буквы.
Теперь, если запросить URL:

http://localhost/myapp_dev.php/mymodule/myAction


Symfony пожалуется на отсутствие шаблона myActionSuccess.php. Это нормально; в symfony страница всегда состоит из действия (action) и шаблона (template).

URL (не доменное имя) — чувствителен к регистру, и следовательно, symfony тоже (даже не смотря на то, что имена методов в PHP не чувствительны к регистру). То есть, если вы создадите метод executemyaction() или executeMyaction(), и потом вызовите через браузер действие (action) myAction, symfony выдаст ошибку 404.

URL — часть пакета ответа (response)


Symfony включает в себя систему роутинга (routing system), которая позволяет полностью управлять связью между именем действия (action) и видом URL, который вызывает это действие. Вы больше не ограничены ни файловой структурой, ни параметрами запроса (request parameters); URL действия будет выглядеть так, как вы пожелайте. Например, вызов главного действия (index action) модуля article обычно выглядит так:

http://localhost/myapp_dev.php/article/index?id=123


Этот URL получает указанную статью (с полем id = 123) из базы данных. Допустим, что эта статья находится в рубрике «Europe» и описывает финансовую сторону жизни Франции. Но URL может выглядеть совершенно по-другому, если сделать небольшие изменения в файле routing.yml:

http://localhost/articles/europe/france/finance.html


Помимо того, что теперь URL стал удобен для поисковых машин (engine-friendly), строка адреса превратилась в некое подобие командной строки, через которую пользователь может делать собственные запросы наподобие:

http://localhost/articles/tagged/finance+france+euro


Symfony знает как обрабатывать и генерировать “красивые” URL. Система роутинга (routing system) автоматически “вынимает” параметры запроса (request parameters) из “красивого” URL, и делает их доступными для действия (action). Она также форматирует ссылки, входящие в пакет ответа (response), таким образом, что они выглядят как “красивые” URL. Вы узнайте больше об этом в Главе 9.

Подытожив, можно сказать, что когда вы даете имя действию (action), вам следует руководствоваться ролью этого действия в приложении, а не тем, как должен выглядеть URL. Имя действия (action) должно соответствовать тому, что это действие (action) делает. Часто названием может послужить глагол (например show, list, edit и т. д.). Имена действий (action) можно полностью скрыть от пользователя, поэтому не стесняйтесь использовать наименования, которые говорят сами за себя (например listByName или showWithComments). Благодаря этому можно не писать большие комментарии к функциями, и код станет более читаемым.

Создание Шаблона


Действию (action) нужен шаблон (template). Шаблон находится в директории модуля templates/, и его название состоит из названия действия (action) и итогового состояния действия (termination). “Success” — итоговое состояние по умолчанию. Поэтому шаблон для действия myAction будет называться myActionSuccess.php.

Шаблоны должны содержать только код, необходимый для вывода данных, поэтому старайтесь по минимуму использовать PHP в шаблонах. Действительно, у странички “Hello, world!” очень простой шаблон, приведенный в Листинге 4–3.

Листинг 4–3 – Шаблон mymodule/templates/myActionSuccess.php
<p>Hello, world!</p>


Если в шаблон нужно добавить PHP код, следует избегать обычного PHP синтаксиса, примером которого может послужить Листинг 4–4. В шаблонах нужно использовать альтернативный синтаксис (приведен в Листинге 4–5), чтобыы код был понятен и тем, кто не знает PHP. Это поможет хранить сложный PHP код в действии (action), потому что только команды, используемые для вывода данных (if, foreach, while, и т. д.), имеют альтернативный синтаксис. К тому же благодаря альтернативному синтаксису, итоговый HTML код будет иметь правильные отступы.

Листинг 4–4 – Обычный PHP Синтаксис, Хорош для Действия (Action), но не Желателен в Шаблоне (Template)
<p>Hello, world!</p>
<?php
 
if ($test)
{
  echo 
"<p>".time()."</p>";
}
 
?>


Листинг 4–5 – В Шаблонах Используется Альтернативный Синтаксис
<p>Hello, world!</p>
<?php if ($test): ?>
<p><?php echo time(); ?></p>
<?php endif; ?>


В шаблоне HTML код не должен выводится через команду echo или через фигурные скобки — этим критерием хорошо пользоваться, чтобы проверить, достаточно ли читаем код шаблона. Почти все время, открывая дескриптор <?php, вы будете закрывать его ?> в той же строке.

Передача Информации из Действия (Action) в Шаблон (Template)


Задача действия (action) выполнить все сложные вычисления, проверки, получить данные из базы, и задать переменные, которые будут выводиться или использоваться для вывода в шаблоне (template). Symfony делает атрибуты action класса (атрибуты доступны из действия (action) как $this->variableName) напрямую доступными из шаблона (template) в глобальном пространстве имен (из шаблона обратиться к атрибутам еще проще: $variableName). Листинг 4–6 и 4–7 показывает как передать информацию из действия (action) в шаблон (template).

Листинг 4–6 – Зададим Атрибуты Action Класса, чтобы Сделать их Доступными в Шаблоне
<?php
 
class mymoduleActions extends sfActions
{
  public function 
executeMyAction()
  {
    
$today getdate();
    
$this->hour $today['hours'];
  }
}


Листинг 4–7 – Из Шаблона (Template) Атрибуты Доступны Напрямую
<p>Hello, world!</p>
<?php if ($hour >= 18): ?>
<p>Or should I say good evening? It's already <?php echo $hour ?>.</p>
<?php endif; ?>


Некоторые данные можно получить из шаблона, не подготавливая загодя переменные в действии (action). В любом шаблоне можно обратиться к объектам $sf_context, $sf_request, $sf_params, и $sf_user. Они хранят в себе информацию о текущем контексте (context), запросе (request), параметрах запроса (request parameters), и сессии (session). Скоро вы узнайте как эффективно использовать эти объекты.

Получение Информации от Пользователя с Помощью Форм


Формы это хороший способ получить информацию от пользователя. Иногда писать формы на HTML довольно тягостно, особенно если требуется соответствие стандартам XHTML. Вы можете создавать формы традиционным способом, так как показано в Листинге 4–8, а можете воспользоваться специальными помощниками (helper) symfony, которые упростят задачу.

Листинг 4–8 – В Шаблонах Можно Использовать Обычный HTML Код
<p>Hello, world!</p>
<?php if ($hour >= 18): ?>
<p>Or should I say good evening? It's already <?php echo $hour ?>.</p>
<?php endif; ?> 
<form method="post" target="/myapp_dev.php/mymodule/anotherAction">
  <label for="name">What is your name?</label>
  <input type="text" name="name" id="name" value="" />
  <input type="submit" value="Ok" />
</form>


Помощники (helper) это PHP функции, определенные в symfony и предназначенные для использования в шаблонах. Эти функции выводят некий HTML код, использовать их значительно удобнее и быстрее, чем самостоятельно писать HTML. В Листинге 4–9 приведен код, который, с помощью функций-помощников, создает формы идентичные формам из Листинга 4–8.

Листинг 4–9 – Использовать помощников (Helper) быстрее и удобнее, чем самостоятельно писать HTML тэги
<p>Hello, world!</p>
<?php if ($hour >= 18): ?>
<p>Or should I say good evening? It's already <?php echo $hour ?>.</p>
<?php endif; ?>
<?php 
echo form_tag('mymodule/anotherAction'?>
  <?php echo label_for('name''What is your name?'?>
  <?php echo input_tag('name'?>
  <?php echo submit_tag('Ok'?>
</form>


Помощники (Helper) нужны чтобыы помочь вам

Если Листинги 4–8 и 4–9 не убедили вас, что использование помощников (helper) вместо написания HTML кода, убыстряет работу, то взгляните на этот пример:
<?php
>     $card_list = array(
>       
'VISA' => 'Visa',
>       
'MAST' => 'MasterCard',
>       
'AMEX' => 'American Express',
>       
'DISC' => 'Discover');
>     echo 
select_tag('cc_type'options_for_select($card_list'AMEX'));
>     
?>


Это выдаcт следующий HTML код:
<select name="cc_type" id="cc_type">
  <option value="VISA">Visa</option>
  <option value="MAST">MasterCard</option>
  <option value="AMEX" selected="selected">American Express</option>
  <option value="DISC">Discover</option>
</select>


Использование помощников (helper) в шаблонах увеличивает скорость написания кода, делает его более понятным и лаконичным. Цена этого состоит лишь в том, что вы должны потратить некоторое время на изучение функций-помощников, то есть прочитать эту книгу. Конечно вы можете не использовать функции-помощники в шаблонах, и по-прежнему писать HTML код, но это будет большая потеря, вы получите гораздо меньше удовольствия от работы.


Не рекомендуется использовать короткий открывающий тэг (<?=, эквивалентно <?php echo) в профессиональных веб приложениях, поскольку сервер может поддерживать несколько скриптовых языков, что может привести к путанице. Кроме того, короткие открывающие теги (<?=) не работают при конфигурации PHP по умолчанию, их использование требует дополнительной подстройки. Еще один аргумент против — при работе с XML и валидацией, это не сработает, так как <? имеет специальное значение в XML.

Формы залуживает отдельной главы, поскольку symfony предоставляет множество инструментов, в основном функций-помощников, для упрощения работы. Подробнее об этом в Главе 10.

Ссылки на Другие Действия (Action)


Вы уже знаете, что разница между именем действия (action) и соответствующим URL может быть очень большой. Если вы создадите ссылку на действие anotherAction в шаблоне, как показано в Листинге 4–10, то при ее обработке будет использован стандартный роутинг (routing). И если позже вы решите изменить вид URL адресов, понадобится пересмотреть все шаблоны и исправить все ссылки.

Листинг 4–10 – Классическая Ссылка
<a href="/myapp_dev.php/mymodule/anotherAction?name=anonymous">
  I never say my name
</a>


чтобы избежать таких трудностей, для создания ссылок на действия (action) вашего приложения, следует пользоваться функцией-помощником link_to(). Листинг 4–11 демонстрирует использование этого помощника.

Листинг 4–11 – Функция-помошник link_to()
<p>Hello, world!</p>
<?php if ($hour >= 18): ?>
<p>Or should I say good evening? It's already <?php echo $hour ?>.</p>
<?php endif; ?>
<?php 
echo form_tag('mymodule/anotherAction'?>
  <?php echo label_for('name''What is your name?'?>
  <?php echo input_tag('name'?>
  <?php echo submit_tag('Ok'?>
  <?php echo link_to('I never say my name','mymodule/anotherAction?name=anonymous'?>
</form>


Результирующий HTML будет такой же, как в предыдущем примере. И при изменении правил системы роутинга, все ссылки во всех шаблонах будут отформатированы соответственно.

Помощник link_to(), как и многие другие функции-помощники, предусматривает необязательный аргумент, для передачи дополнительных параметров или атрибутов тэга. Пример использования такого аргумента и результирующий HTML приведены в Листинге 4–12. Необязательный аргумент это или ассоциативный массив, или просто строка, хранящяя через пробел пары вида ключ=значение.

Листинг 4–12 – Большинство Функций-Помощников Предусматривают Необязательный Аргумент
// Аргумент задается как строка
<?php echo link_to('I never say my name''mymodule/anotherAction?name=anonymous',
  array(
    
'class'    => 'special_link',
    
'confirm'  => 'Are you sure?',
    
'absolute' => true
)) ?>
 
// Аргумент задается как массив
<?php echo link_to('I never say my name''mymodule/anotherAction?name=anonymous',
  
'class=special_link confirm=Are you sure? absolute=true'?>
 
// Оба способа выдают одинаковый код
 => <a class="special_link" onclick="return confirm('Are you sure?');"
    href="http://localhost/myapp_dev.php/mymodule/anotherAction/name/anonymous">
    I never say my name</a>


Всякий раз, когда вы используйте функцию-помощник, выводящую HTML тэги, вы можете задать дополнительные атрибуты тэга (как например атрибут class в примере из Листинга 4–12) в необязательном аргументе. Вы даже можете задать эти атрибуты в стиле «quick-and-dirty» HTML 4.0 («быстрый-и-грязный» HTML 4.0; без двойных ковычек), и symfony выведет их в красиво отформатированном XHTML. Это еще одна причина, по которой написание HTML уступает функциям-помощникам в скорости.

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


Помощников отвечающих за ссылки (Глава 9 описывает их детально) много и у них есть множество опций. То же можно сказать о функциях-помощниках для форм.

Получение Информации из Запроса


Независимо от того, как пришла информация от пользователя, через форму (обычно это POST запрос), или через URL (GET запрос), вы можете получить данные запроса из действия (action) с помощью метода getRequestParameter() объекта sfActions. Листинг 4–13 показывает, как получить значение параметра name в действии anotherAction.

Листинг 4–13 – Получение Данных из Запроса в Действии (Action)
<?php
 
class mymoduleActions extends sfActions
{
  ...
 
  public function 
executeAnotherAction()
  {
    
$this->name $this->getRequestParameter('name');
  }
}


Если обработка данных проста, вам даже может не понадобиться использовать действие (action) для получения параметров запроса (request). Из шаблона (template) доступен объект $sf_params, у которого есть метод get() для получения параметров запроса, аналогичный методу getRequestParameter(), который мы использовали в действии (action).

Листинг 4–14 показывает, как можно получить параметр name из шаблона anotherActionSuccess.php, если метод executeAnotherAction() пустой.

Листинг 4–14 Демонстрирует как Получить Параметр Запроса Напрямую из Шаблона
<p>Hello, <?php echo $sf_params->get('name'?>!</p>


Почему нельзя использовать для этих целей переменные $_POST, $_GET, или $_REQUEST? Потому что URL отформатирован по-другому (как например http://localhost/articles/europe/france/finance.html, без символов ? и =), обычные переменные PHP теперь не будут работать, и только система роутинга (routing) позволяет получить параметры запроса (request parameters). К тому же, вам может понадобиться фильтровать входящие данные для защиты от злоумышленной инъекции кода, что возможно только, если вы храните все параметры в одном, правильно сконструированном, контейнере параметров.


Объект $sf_params располагает, не только методами доступа (getter методы) но и более мощными средствами. Например, если вы хотите проверить существование какого либо параметра запроса, воспользуйтесь методом $sf_params->has() вместо того чтобы собственноручно проверять значение с помощью метода get(), как сделано в Листинге 4–15.

Листинг 4–15 – Проверка Существования Параметра Запроса в Шаблоне
<?php if ($sf_params->has('name')): ?>
  <p>Hello, <?php echo $sf_params->get('name'?>!</p>
<?php else: ?>
  <p>Hello, John Doe!</p>
<?php endif; ?>


Вы уже наверное догадались, что Листинг 4–15 можно уместить в одну строчку кода. Как и все методы доступа (getter методы) в symfony, метод getRequestParameter() в действии (action) и метод $sf_params->get() в шаблоне (который, между прочим, вызывает тот же метод того же объекта) допускают передачу второго аргумента: значения, которое используется, если параметр запроса (request parameter) не определен.

<p>Hello, <?php echo $sf_params->get('name''John Doe'?>!</p>


Итого


В symfony, страницы состоят из действия (метод в файле actions/actions.class.php с префиксом execute) и шаблона (файл в директории templates/, имя которого обычно заканчивается как Success.php). Страницы сгруппированы в модули, согласно тому, какую функцию они выполняют в приложении. Написание шаблонов упрощается благодаря помощникам, которых предоставляет symfony, и которые являются функциями, возвращающими HTML код. URL нужно воспринимать как часть пакета ответа (response), которую можно отформатировать как вы захотите. Поэтому лучше воздержаться от использования прямых ссылок на действия (action), и от получения параметров запроса (request parameter) напрямую.

Теперь, когда вы знаете эти основные принципы, вы можете написать целое приложение на symfony. Но это займет много времени, так как достижение почти каждой задачи, которые возникнут в этом курсе разработки приложений, упрощается с помощью той или иной возможности symfony, которые еще предстоит освоить... вот почему книга не заканчивается на этой главе.

1 2 3 4 5

Последние комментарии:

не выводит он John Doe почему-то dmx_
Уважаемые, не подскажете?

Есть ещё энтузиасты переводчики!!! Albatros
на офф. сайте симфони выложены ещё главы перевода
http://www.symfony-project.com/translated_book/1_0/ru_RU

Уже предлогали... Albatros
на sfproject переводчик гордый... хочет сам переводить...
правда разбились бы по частям, а потом допереводили уже оставшиеся... а так... каждый перевёл по 4 главы, вдвоём перевели 8... эх...
ушел учить англицкий...
кстати, на англицком документация периодически корректируется...

guest
на http://sfproject.ru доступен другой вариант перевода 4 глав... первых..
вместо того чтобы было бы уже 8 переведено, есть только 4, может вам объединиться?

Обсудить (комментариев: 4)