Skip to content

Latest commit

 

History

History
141 lines (111 loc) · 14.1 KB

ControllerBasics.md

File metadata and controls

141 lines (111 loc) · 14.1 KB

Основы контроллеров

На базовом уровне контроллеры - это код, который выполняется при посещении страницы в XF. Контроллеры обычно отвечают за обработку пользовательских данных и передачу этих данных в соответствующий метод, который, как правило, должно выполнить какое-либо действие с базой данных(моделью) или загрузить визуальное содержимое(представление).

Когда пользователь переходит по ссылке, запрошенный URL-адрес вызывает определенный контроллер и метод контроллера. Смотрите Основы маршрутизации. Например, в XF, если посетить URL-адрес index.php?conversations/add будет вызван контоллер XF\Pub\Controller\Conversation и метод(action) add.

Если вы посмотрите на содержимое этого класса (описание сопоставления классов и путей к файлам см.В разделе АвтоЗагрузчик) вы заметите, что методы именуются с префиксом action. Эти методы вызывают определенное действие контроллера. Таким образом, чтобы увидеть метод, участвующий при просмотре страницы conversations/add , смотрите public function actionAdd().

Контроллеры XF возвращают объект ответа, который может быть следующих типов:

Ответ "Представление(view)"

Это один из наиболее распространенных ответов, с которым вы будете иметь дело во время разработки XF. Контроллер, который возвращает ответ представление(view), обычно требует передачу трех аргументов. Класс представления (подробнее об этом ниже), имя шаблона и массив $viewParams - это переменные, которые будут доступны в шаблоне.

Это пример действия контроллера, который возвращает ответ представление(view):

public function actionExample()
{
    $hello = 'Hello';
    $world = 'world!';

    $viewParams = [
        'hello' => $hello,
        'world' => $world
    ];
    return $this->view('Demo:Example', 'demo_example', $viewParams);
}

Первый аргумент - это короткое имя класса представления. Этот класс может даже не существовать (часто он не должен существовать, мы рассмотрим классы представлений позже), но он должен иметь уникальное имя для контроллера и метода. Подобно другим Коротким именам классов, приведенное выше,также преобразуется в Demo\Pub\View\Example. Опять же, Pub выводится автоматически из типа контроллера.

Второй аргумент - имя шаблона. В этом случае мы ищем шаблон с именем demo_example.

Третий аргумент представляет собой массив параметров/переменных шаблона, которые доступны представлению(view). Этот массив должен быть парой key => value (ключ => значение). В приведенном выше примере в шаблон передаются два параметра. Ключ (key) указывает имя переменной, доступной в шаблоне. Значение массива (value) указывает на значение параметра.

Итак, если бы в шаблоне demo_example было следующее содержимое:

{$hello} {$world}

Шаблон выведет следующее:

Hello world!

Ответ "Перенаправление(redirect)"

Этот ответ возвращают, когда вы хотите перенаправить пользователя на другой URL-адрес после выполнения какого-либо действия.

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

Это пример действия контроллера, который возвращает перенаправление(redirect):

public function actionRedirect()
{
    return $this->redirect($this->buildLink('demo/example'), 'This is a redirect message.', 'permanent');
}

Первый аргумент - URL для перенаправления. Данный пример перенаправит пользователя к index.php?demo/example .

Второй аргумент будет отображаться только в том случае, если форма передается по AJAX-запросу, который запрещает перенаправление. Результатом будет "flash-сообщение", которое появится в верхней части экрана. Можно не указывать собственное сообщение. Тогда, по умолчанию будет "Ваши изменения были сохранены".

Третий аргумент по умолчанию имеет значение temporary, но вы также можете установить его в permanent в соответствии с примером выше. Единственное отличие здесь - это код ответа HTTP сервера. Temporary идеально подходит в большинстве случаев, и он будет отвечать 303 кодом. permanent будет отвечать 301 кодом.

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

public function actionRedirect()
{
    return $this->redirectPermanently($this->buildLink('demo/example'));
}

Ответ "Ошибка(error)"

Как следует из названия, этот ответ - отобразит пользователю ошибку. Вот небольшой пример:

public function actionError()
{
    return $this->error('Unfortunately the thing you are looking for could not be found.', 404);
}

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

Ответ "Сообщение(message)"

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

Ответ "Исключение(exception)"

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

public function actionException()
{
    throw $this->exception($this->error('An unexpected error occurred'));
}

Исключения принимают только один аргумент, и он должен быть каким-либо другим объектом ответа, такой как Ответ "Ошибка". Данный конкретный пример бросает исключение, и весь код контроллера в той точке остановится, и будет отображена стандартная ошибка.

Обратите внимание, что ответы на исключения должны быть "брошены" с помощью throw, а не "возвращены" return .

Ответ "Перенаправление маршрута(reroute)"

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

Это выглядит примерно так:

public function actionReroute()
{
    return $this->rerouteController(__CLASS__, 'error');
}

public function actionError()
{
    return $this->error('Oops! Something went wrong!');
}

В данном примере, если пользователь посетил index.php?demo/reroute, они увидят ответ об ошибке из метода actionError(). Они не будут перенаправлены, и URL-адрес в их браузере не изменится; они просто получат ответ от actionError().

Ответ reroute также поддерживает третий аргумент, который позволяет передавать различные параметры от одного метода контроллера к другому. Это может быть массив или объект ParameterBag (об этом позже).

Правильное изменение ответа на действие контроллера

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

Если у вас нет задачи полностью переопределить/изменить существующий метод(что не рекомендуется), вместо этого вы должны изменить существующий ответ родительского класса. Это делается довольно просто, в качестве примера давайте изменим код Ответ "Просмотр" из примера выше.

public function actionExample()
{
    $reply = parent::actionExample();

    return $reply;
}

Предполагая, что вышеупомянутое добавлено к расширенному контроллеру, где метод actionExample() уже существует, вышеприведенный код ничего не делает, кроме возврата исходного ответа. Теперь изменим существующий параметр hello на Bonjour.

public function actionExample()
{
    $reply = parent::actionExample();

    if ($reply instanceof \XF\Mvc\Reply\View)
    {
        $reply->setParam('hello', 'Bonjour');
    }

    return $reply;
}

Поскольку ответ контроллера может фактически представлять несколько различных объектов с различным поведением и методами, крайне важно, чтобы мы только попытались расширить правильный тип ответа. Мы делаем это в приведенном выше примере, проверяя, является ли родительский объект $reply типом представления(view). Если бы мы не сделали этого, и расширили метод, а метод отвечал бы перенаправлением - была бы ошибка.

Перед расширением этого действия, посетив эту страницу будет отображаться "Hello world!". После его расширения, будет отображаться "Bonjour world!".