Caution: You are browsing the legacy symfony 1.x part of this website.

День 4: Вид и контроллер

Ранее на Jobeet

Вчера мы изучали как Symfony упрощает управление БД, абстрагируя разницу между движками баз данных и конвертируя связанные элементы в прекрасные объекто-ориентированные классы. Мы уже также успели пощупать Propel, описывая схему базы данных, создавая таблицы и заводя некоторые начальные данные.

Сегодня мы будем изменять базовый модуль job, созданный вчера. Модуль job уже имеет весь необходимый код для Jobeet:

  • Страницу со списком вакансий
  • Страницу создания вакансии
  • Страницу обновления вакансии
  • Страницу удаления вакансии

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

Архитектура MVC

Если Вы привыкли создавать сайты на PHP без применения фреймворка, то возможно Вы используете парадигму, в которой один PHP-файл соответствует одной веб-странице. Возможно данные PHP-файлы содержат схожую структуру: инициализация и глобальные настройки, бизнес-логика привязана к текущей странице, получение записей из БД и конечно же HTML код, который выстраивает страницу.

Возможно Вы используете шаблонизатор для отделения логики от HTML. Возможно Вы используете слой абстракции баз данных, для отделения моделей от бизнес-логики. Но в большинстве случаев всё заканчивается огромным количеством кода, поддерживать который - сущий кошмар. Создать было просто, а вот вносить новые изменения становится все труднее и труднее, особенно если никто, кроме Вас, не понимает как это сделано и как это работает.

Для каждой проблемы всегда есть красивое решение. Для веб-разработок одним из лучших способов организации кода в наше время является шаблон проектирования MVC. Если коротко, то шаблон проектирования MVC определяет способ организации вашего кода в зависимости от его назначения. Шаблон разделяет код на три слоя:

  • Model (Модель) - определяет бизнес-логику (база данных относится к данному слою). Вы уже знаете о том, что Symfony хранит все классы, связанные с моделью в каталоге lib/model.

  • View (Представление) - это то, с чем работает пользователь (шаблонный движок являются частью данного слоя). В Symfony представления по большей части основаны на PHP-шаблонах. Они хранятся в различных каталогах templates, в чём мы убедимся чуть позже.

  • Controller (Контроллер) - это часть кода, которая вызывает модель для получения данных, которые уже передаёт представлению для их обработки и выдачи клиенту. Когда мы установили Symfony в первый день, то мы увидели, что все запросы принимаются фронт-контроллерами (index.php и frontend_dev.php). Данные фронт-контроллеры делегируют обработку контроллерам (actions). Вчера мы узнали, что действия логически сгруппированы в модули.

MVC

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

Обёртка

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

Одним из путей решения этой проблемы является определение заголовка (header) и подвала страницы (footer) и вставка их в каждый из шаблонов.

Хедер и футер

Только вот в данном случае файлы заголовка и подвала не содержат верного HTML. Должен быть лучший способ. Вместо изобретения велосипеда, мы используем другой дизайн-шаблон для решения проблемы: Декоратор (Decorator). Декотратор решает проблему обходным путём: шаблон обрамляется другим общим шаблоном, после того, как готово всё содержимое. Данный шаблон называется в Symfony основным шаблоном (layout):

Layout

Стандартный шаблон в приложении называется layout.php и может быть найден в каталоге apps/frontend/templates/. Данный каталог содержит все общие (глобальные) шаблоны приложения.

Замените текущий шаблон Symfony следующим кодом:

<!-- apps/frontend/templates/layout.php -->
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  <head>
    <title>Jobeet - Your best job board</title>
    <link rel="shortcut icon" href="/favicon.ico" />
    <?php include_javascripts() ?>
    <?php include_stylesheets() ?>
  </head>
  <body>
    <div id="container">
      <div id="header">
        <div class="content">
          <h1><a href="/job">
            <img src="/legacy/images/jobeet.gif" alt="Jobeet Job Board" />
          </a></h1>
 
          <div id="sub_header">
            <div class="post">
              <h2>Ask for people</h2>
              <div>
                <a href="/job/new">Post a Job</a>
              </div>
            </div>
 
            <div class="search">
              <h2>Ask for a job</h2>
              <form action="" method="get">
                <input type="text" name="keywords" id="search_keywords" />
                <input type="submit" value="search" />
                <div class="help">
                  Enter some keywords (city, country, position, ...)
                </div>
              </form>
            </div>
          </div>
        </div>
      </div>
 
      <div id="content">
        <?php if ($sf_user->hasFlash('notice')): ?>
          <div class="flash_notice"><?php echo $sf_user->getFlash('notice') ?></div>
        <?php endif; ?>
 
        <?php if ($sf_user->hasFlash('error')): ?>
          <div class="flash_error"><?php echo $sf_user->getFlash('error') ?></div>
        <?php endif; ?>
 
        <div class="content">
          <?php echo $sf_content ?>
        </div>
      </div>
 
      <div id="footer">
        <div class="content">
          <span class="Symfony">
            <img src="/legacy/images/jobeet-mini.png" />
            powered by <a href="http://www.Symfony-project.org/">
            <img src="/legacy/images/Symfony.gif" alt="Symfony framework" /></a>
          </span>
          <ul>
            <li><a href="">About Jobeet</a></li>
            <li class="feed"><a href="">Full feed</a></li>
            <li><a href="">Jobeet API</a></li>
            <li class="last"><a href="">Affiliates</a></li>
          </ul>
        </div>
      </div>
    </div>
  </body>
</html>

Шаблон Symfony это обычный PHP-файл. В основном шаблоне Вы увидите вызовы PHP функций и ссылки на переменные. $sf_content самая интересная переменная - она определяется фреймворком и содержит весь HTML-код, созданный действием контроллера.

Если Вы взглянете теперь на модуль job (http://jobeet.localhost/frontend_dev.php/job), то увидите, что все действия теперь обрамлены шаблоном.

note

В шаблоне мы прописали favicon. Вы можете скачать иконку Jobeet и разместить её в каталоге web/.

Стили, изображение, Javascript

Мы подготовили самый базовый дизайн для текущего использования: здесь можно скачать изображения и разместить их в директорию web/legacy/images/; вот тут файлы стилей, которые стоит разместить в директорию web/css/.

Модуль вакансии с шаблоном, картинками и стилями

tip

Команда generate:project создала для нас 3 директории для файлов проекта: web/legacy/images/ для изображений, web/css/ для стилей и web/js/ для JavaScript'ов. Это одно из нескольких правил, определяемых Symfony. Но никто Вам не запрещает хранить файлы в любом месте каталога web/

Внимательный читатель скорей всего заметил, что даже файл main.css, который нигде не упоминается в шаблоне, появляется в полученном HTML/ А вот другие стили - нет. Как такое возможно?

Файлы стилей встраиваются при помощи функции include_stylesheets(), вызов которой можно обнаружить в теге <head>. Функция include_stylesheets() называется помощник (helper). Помощник это функция, определённая в Symfony, которая принимает параметры и возвращает HTML код. В большинстве случаев помощники помогают экономить время, они содержать небольшие кусочки кода, переодически используемые в шаблонах. Помощник include_stylesheets() создаёт тег <link> для стилей.

Но откуда помощнику известно, какие файл стилей нужно использовать?

Представление может быть настроено при помощи редактирования файла конфигурации приложения view.yml. Вот стандартное содержимое файла, получаемое после использования команды generate:app:

# apps/frontend/config/view.yml
default:
  http_metas:
    content-type: text/html
 
  metas:
    #title:        Symfony project
    #description:  Symfony project
    #keywords:     Symfony, project
    #language:     en
    #robots:       index, follow
 
  stylesheets:    [main.css]
 
  javascripts:    []
 
  has_layout:     on
  layout:         layout

Файл view.yml определяет стандартные настройки для всех шаблонов приложения. Например, опция stylesheets определяет массив файлов стилей, которые будут включены на каждой странице приложения (включение осуществляется при помощи помощника include_stylesheets()).

note

В стандартном файле view.yml идёт ссылка на main.css, а не на /css/main.css Но оба этих определения равны, потому что Symfony приписывает к относительному пути /css/.

В случае, если у нас определены несколько файлов, Symfony включит их в том порядке, в каком они были определены:

stylesheets:    [main.css, jobs.css, job.css]

Вы также можете изменить атрибут media и поставить расширение отличное от .css:

stylesheets:    [main.css, jobs.css, job.css, print: { media: print }]

Данная конфигурация будет отображена как:

<link rel="stylesheet" type="text/css" media="screen" href="/css/main.css" />
<link rel="stylesheet" type="text/css" media="screen" href="/css/jobs.css" />
<link rel="stylesheet" type="text/css" media="screen" href="/css/job.css" />
<link rel="stylesheet" type="text/css" media="print" href="/css/print.css" />

tip

файл конфигурации view.yml так же определяет стандартный шаблон, который будет использоваться приложением. Изначально его имя layout и Symfony обрамляет каждую страницу файлом layout.php. Вы можете вообще отменить процесс декорирования изменив опцию has_layout на false.

Всё что нам сейчас нужно, это чтобы файл jobs.css был прикручен к главной странице, а job.css к странице с вакансиями. Файл view.yml может быть изменён отдельно для каждого модуля. Измените view.yml так, чтобы он содержал лишь файл main.css:

# apps/frontend/config/view.yml
stylesheets:    [main.css]

Чтобы изменить вид модуля job, создайте файл view.yml в каталоге apps/frontend/modules/job/config/:

# apps/frontend/modules/job/config/view.yml
indexSuccess:
  stylesheets: [jobs.css]
 
showSuccess:
  stylesheets: [job.css]

Под частями indexSuccess и showSuccess (это имена шаблонов, который связаны с действиями index и show, о чём мы узнаем позже), Вы можете изменять любую из опций, находящихся в default в файле view.yml, относящемуся к приложению. Все данные опции будут частью конфигурации приложения. Вы так же можете определить конфигурациию для всех действий модуля при помощи раздела all.

sidebar

Принципы конфигурации в Symfony

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

  • Конфигурация по умолчанию расположена во фреймворке
  • Общая конфигурация проекта (лежит в config/)
  • Конфигурация приложения (в apps/APP/config/)
  • Конфигурация отдельного модуля (можно найти по адресу apps/APP/modules/MODULE/config/)

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

Правило большого пальца: если что-то где можно настроить через файлы конфигурации, то же самое можно сделать и через код PHP. Вместо создания view.yml для модуля job можно использовать помощник use_stylesheet() для вставки стиля в шаблон:

<?php use_stylesheet('main.css') ?>

Вы также можете использовать этот помощник в шаблоне, для вставки общих стилей.

Использовать ли один способ, или другой - дело вкуса. Файл view.yml предоставляет способ определения параметров для всех действий модуля, что невозможно в отдельном шаблоне, но конфигурация абсолютно статична. С другой стороны, использование помощника use_stylesheet() более гибкое и помимо этого всё в одном месте: и стили, и HTML код. В Jobeet мы будет применять помощники use_stylesheet(), так что Вы можете удалить view.yml, который мы только что создали, и обновить шаблоны модуля job, внеся туда вызовы use_stylesheet().

note

Пареллельно этому, конфигурация JavaScript осуществляется через опцию javascripts в файле view.yml и через помощник use_javascript() для определения JavaScript файлов в шаблоне.

Главная страница вакансий

Как мы уже видели в третьем дне, главная страница вакансий генерируется действием index модуля job. Действие index это часть контроллера страницы и оно связано с шаблоном indexSuccess.php, который является представлением:

apps/
  frontend/
    modules/
      job/
        actions/
          actions.class.php
        templates/
          indexSuccess.php

Действие

Каждое действие определено методом класса. Для главной страницы вакансий есть класс jobActions (к имени модуля прибавляется Actions), а так же метод executeIndex() (execute прибавляется к имени действия). Данное действие получает все вакансии из БД:

// apps/frontend/modules/job/actions/actions.class.php
class jobActions extends sfActions
{
  public function executeIndex(sfWebRequest $request)
  {
    $this->jobeet_job_list = JobeetJobPeer::doSelect(new Criteria());
  }
 
  // ...
}

Давайте взглянем поближе на код: метод executeIndex() (контроллер) вызывает модель JobeetJobPeer для получения всех вакансий (new Criteria()). Последняя возвращает массив объектов JobeetJob, которые привязаны к к свойству объекта jobeet_job_list.

Все подобные свойства объекта в дальнейшем передаются шаблону (представление). Для того чтобы передать данные из контроллера в представление, просто создайте ещё одно свойство:

public function executeIndex(sfWebRequest $request)
{
  $this->foo = 'bar';
  $this->bar = array('bar', 'baz');
}

Данный код сделает переменные $foo и $bar доступными для шаблона.

Шаблон

Изначально, названия шаблонов, связанных с действиями, определяются Symfony благодаря правилам (к действию прибавляется Success).

Шаблон indexSuccess.php создаёт HTML таблицу для вывода всех вакансий:

<!-- apps/frontend/modules/job/templates/indexSuccess.php -->
<h1>Job List</h1>
 
<table>
  <thead>
    <tr>
      <th>Id</th>
      <th>Category</th>
      <th>Type</th>
<!-- more columns here -->
      <th>Created at</th>
      <th>Updated at</th>
    </tr>
  </thead>
  <tbody>
    <?php foreach ($jobeet_job_list as $jobeet_job): ?>
    <tr>
      <td>
        <a href="<?php echo url_for('job/show?id='.$jobeet_job->getId()) ?>">
          <?php echo $jobeet_job->getId() ?>
        </a>
      </td>
      <td><?php echo $jobeet_job->getCategoryId() ?></td>
      <td><?php echo $jobeet_job->getType() ?></td>
<!-- more columns here -->
      <td><?php echo $jobeet_job->getCreatedAt() ?></td>
      <td><?php echo $jobeet_job->getUpdatedAt() ?></td>
    </tr>
    <?php endforeach; ?>
  </tbody>
</table>
 
<a href="<?php echo url_for('job/new') ?>">New</a>

В коде шаблона, foreach пробегается по всем объектам Job ($jobeet_job_list) и выводит для каждой вакансии каждое значения поля. Помните, получить доступ к значению поля просто - через вызов метода доступа, имя которого начинается с get и camelCased имени поля (например getCreatedAt() для поля created_at).

Давайте немного приберёмся в коде и организуем вывод лишь значений определённого набора доступных полей:

<!-- apps/frontend/modules/job/templates/indexSuccess.php -->
<?php use_stylesheet('jobs.css') ?>
 
<div id="jobs">
  <table class="jobs">
    <?php foreach ($jobeet_job_list as $i => $job): ?>
      <tr class="<?php echo fmod($i, 2) ? 'even' : 'odd' ?>">
        <td><?php echo $job->getLocation() ?></td>
        <td>
          <a href="<?php echo url_for('job/show?id='.$job->getId()) ?>">
            <?php echo $job->getPosition() ?>
          </a>
        </td>
        <td><?php echo $job->getCompany() ?></td>
      </tr>
    <?php endforeach; ?>
  </table>
</div>

Главная страница

Функция url_for() это очередной помощник, который мы обсудим завтра.

Шаблон отображения вакансии

А теперь изменим шаблон страницы с вакансией. Откройте файл showSuccess.php и замените его содержимое следующим:

<?php use_stylesheet('job.css') ?>
<?php use_helper('Text') ?>
 
<div id="job">
  <h1><?php echo $job->getCompany() ?></h1>
  <h2><?php echo $job->getLocation() ?></h2>
  <h3>
    <?php echo $job->getPosition() ?>
    <small> - <?php echo $job->getType() ?></small>
  </h3>
 
  <?php if ($job->getLogo()): ?>
    <div class="logo">
      <a href="<?php echo $job->getUrl() ?>">
        <img src="<?php echo $job->getLogo() ?>"
          alt="<?php echo $job->getCompany() ?> logo" />
      </a>
    </div>
  <?php endif; ?>
 
  <div class="description">
    <?php echo simple_format_text($job->getDescription()) ?>
  </div>
 
  <h4>How to apply?</h4>
 
  <p class="how_to_apply"><?php echo $job->getHowToApply() ?></p>
 
  <div class="meta">
    <small>posted on <?php echo $job->getCreatedAt('m/d/Y') ?></small>
  </div>
 
  <div style="padding: 20px 0">
    <a href="<?php echo url_for('job/edit?id='.$job->getId()) ?>">Edit</a>
  </div>
</div>

Данный шаблон использует переменную $job, которая передаётся действием, для отображения информации о вакансии. Так как мы переименовали переменную, передаваемую шаблону с $jobeet_job на $job, тоже самое нам нужно сделать в дейстиии show (будьте бдительны, эта переменная попадается нам дважды):

// apps/frontend/modules/job/actions/actions.class.php
public function executeShow(sfWebRequest $request)
{
  $this->job = JobeetJobPeer::retrieveByPk($request->getParameter('id'));
  $this->forward404Unless($this->job);
}

Смею заметить, что методы доступа Propel принимают аргументы. Мы определили поле created_at как timestamp, поэтому метод getCreatedAt() принимает шаблон формата даты как первый аргумент:

$job->getCreatedAt('m/d/Y');

note

Описание вакансии использует помощник simple_format_text() для форматирования HTML, заменяя переносы строка на <br />, например. Так как данный помощник относится к группе помощников Text, который изначально не загружается, то нам придётся загрузить его самим при помощи помощника use_helper().

Слоты

На данный момент все заголовки на всех страницах в теге <title> шаблона layout выглядят так:

<title>Jobeet - Your best job board</title>

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

В Symfony, когда зона шаблона layout зависит от отображаемого шаблона, то мы должны определить слот:

Slots

Добавьте слот в шаблон, чтобы сделать заголовок более динамичным:

// apps/frontend/templates/layout.php
<title><?php include_slot('title') ?></title>

Каждый слот определяется именем (title) и может быть отображен при помощи помощника include_slot(). Теперь в начале шаблона showSuccess.php используем помощник slot(), чтобы определить содержимое слота на странице вакансии:

// apps/frontend/modules/job/templates/showSuccess.php
<?php slot('title', sprintf('%s is looking for a %s', $job->getCompany(), $job->getPosition())) ?>

Если заголовок сложен в генерации, то помощник slot() можно использовать в виде блока:

// apps/frontend/modules/job/templates/showSuccess.php
<?php slot('title') ?>
  <?php echo sprintf('%s is looking for a %s', $job->getCompany(), $job->getPosition()) ?>
<?php end_slot(); ?>

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

// apps/frontend/templates/layout.php
<title>
  <?php if (!include_slot('title')): ?>
    Jobeet - Your best job board
  <?php endif; ?>
</title>

Помощник include_slot() возвращает true, если слот был определён. Так что, когда Вы определяете содержимое слота title в шаблоне, то используется оно; если нет, что используется заголовок по умолчанию.

tip

Мы уже познакомились с несколькими помощниками, начинающимися с include_. Эти помощники выводят HTML и в большинстве случаев имеются сопряжённые помощники get_, которые просто напросто возвращают контент.

<?php include_slot('title') ?>
<?php echo get_slot('title') ?>
 
<?php include_stylesheets() ?>
<?php echo get_stylesheets() ?>

Страница вакансии

Страница вакансии генерируется действием show, определённым в методе executeShow() модуля job:

class jobActions extends sfActions
{
  public function executeShow(sfWebRequest $request)
  {
  $this->job = JobeetJobPeer::retrieveByPk($request->getParameter('id'));
    $this->forward404Unless($this->job);
  }
 
  // ...
}

В действии index класс JobeetJobPeer используется для получения вакансии, в данном случае через метод retrieveByPk(). Параметром данного метода является первичный ключ вакансии. Далее мы объясним почему выражение $request->getParameter('id') возвращает этот ключ.

tip

Сгенерированные классы моделей содержат много полезных методов для взаимодействия с объектами проекта. Найдите время для просмотра кода, расположенного в каталоге lib/om/ и раскройте всю силу, встроенную в эти классы.

Если вакансия не существует в БД, то стоит перенаправить пользователя на страницу 404, чем и занимается метод forward404Unless(). Он принимает Boolean в виде первого параметра и, до тех пор пока не он не будет true, останавливает исполнение текущего процесса. Методы перенаправления останавливают исполнение скрипта, выкидывая исключение sfError404Exception, поэтому не нужно в последствии ничего возвращать.

В случае исключения страница будет отображаться по разному в окружениях prod и dev:

404 error in the dev environment

404 error in the prod environment

note

Прежде чем мы развернем сайт Jobeet на рабочий сервер, Вам придётся научиться изменять основную страницу 404.

sidebar

Семейство методов "forward"

Вызов метода forward404Unless равоносилен следующему:

$this->forward404If(!$this->job);

Что в свою очередь равно:

if (!$this->job)
{
  $this->forward404();
}

Сам по себе метод forward404() лишь ярлык для:

$this->forward('default', '404');

Метод forward() перенаправляет запрос на другое действие этого же приложения; в предыдущем примере на действие 404 модуля default. Модуль default поставляется с Symfony и несёт в себе основные действия для страниц 404, безопасности и авторизации.

Запрос и ответ

Когда Вы попытаетесь запустить в браузере /job или job/show/id/1/, то Вы запускаете кругосветное путешествие по веб-серверу. Браузер посылает запрос, а сервер посылает обратно ответ.

Мы уже видели, что Symfony инкапсулирует запрос в объект sfWebRequest (смотрите подпись к методу executeShow()). И в Symfony, как в объекто-ориентированном фрейморке, ответ также является объектом класса sfWebResponse. Вы можете получить доступ к объекту ответа в действии, вызвав $this->getResponse().

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

note

Почему Symfony оборачивает функционал PHP своими классами? Во-первых, потому что методы Symfony более мощные, чем их PHP аналоги. Затем, потому что, когда Вы тестируете приложение, куда проще эмулировать объекты запроса или ответа, чем пытаться бегать вокруг глобальных переменных или работать с PHP функциями, вроде header(), которые оставляют кучу магии нераскрытой.

The Request

Класс sfWebRequest собирает глобальные массивы $_SERVER, $_COOKIE, $_GET, $_POST, и $_FILES PHP:

Method name PHP equivalent
getMethod() $_SERVER['REQUEST_METHOD']
getUri() $_SERVER['REQUEST_URI']
getReferer() $_SERVER['HTTP_REFERER']
getHost() $_SERVER['HTTP_HOST']
getLanguages() $_SERVER['HTTP_ACCEPT_LANGUAGE']
getCharsets() $_SERVER['HTTP_ACCEPT_CHARSET']
isXmlHttpRequest() $_SERVER['X_REQUESTED_WITH'] == 'XMLHttpRequest'
getHttpHeader() $_SERVER
getCookie() $_COOKIE
isSecure() $_SERVER['HTTPS']
getFiles() $_FILES
getGetParameter() $_GET
getPostParameter() $_POST
getUrlParameter() $_SERVER['PATH_INFO']
getRemoteAddress() $_SERVER['REMOTE_ADDR']

Мы уже получали доступ к параметрам запроса через метод getParameter(). Она нам вернул значение из глобальных массивов $_GET или $_POST или же из переменной PATH_INFO.

Если Вы хотите быть уверены в том, что параметр запроса приходит из определённой переменной, то стоит воспользовать методами getGetParameter(), getPostParameter() и getUrlParameter().

note

Когда Вы хотите запретить действию определённый метод, например когда Вы хотите быть уверены в том, что форма пришла методом POST, то Вы можете использовать метод isMethod(): $this->forwardUnless($request->isMethod('POST'));.

Ответ

Класс sfWebResponse вбирает в себя методы header() и setrawcookie():

Method name PHP equivalent
setCookie() setrawcookie()
setStatusCode() header()
setHttpHeader() header()
setContentType() header()
addVaryHttpHeader() header()
addCacheControlHttpHeader() header()

Конечно же класс sfWebResponse так же предоставляет возможность устанавливать контент в ответе (setContent()) и отправлять ответ браузеру (send()).

Сегодня, чуть ранее, мы видели как можно управлять файлами стилей и JavaScript в обоих представлениях view.yml и в шаблонах. В конце концов, обе техники отвечают методам addStylesheet() и addJavascript() объекта ответа.

tip

Классы sfAction, sfRequest и sfResponse имеют ещё много замечательных методов. Не стесняйтесь и взгляните на них в документации API чтобы знать больше про встроенные в Symfony классы.

Увидимся завтра!

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

Завтра мы узнаем больше о помощнике url_for(), который сегодня использовали, и о маршрутизации, связанной с ним.