Я создаю как веб-приложение Symfony 2.6, так и библиотеку композиторов. Библиотека композитора ничего не знает о Symfony и нуждается в работе с другими фреймворками (или вообще без фреймворка).
В какой-то момент библиотека должна перенаправить пользователя. Конечно, в простой библиотеке естественно называть PHP- header('Location: x')
. Это отлично работает при тестировании библиотеки с прямым PHP и без фреймворка. Но в приложении Symfony контроллер, вызывающий библиотеку, все равно должен создать объект Response
и вернуть его. Фактически создание пустого Response
завершает очистку перенаправления. Я предполагаю, что классы Symfony создают совершенно новый набор заголовков, перезаписывая набор Location
в библиотеке.
Итак, не заставляя мою библиотеку зависить от Symfony, как она может перенаправить пользователя?
Используйте интерфейс, который ваша библиотека определяет и использует посредством инъекции зависимостей.
interface Redirector {
public function redirect($location, $code);
}
В своей библиотеке вы можете передать его как аргумент конструкторам классов, например:
class FooBar {
private $redirector;
public function __construct(Redirector $red) {
$this->redirector = $red;
}
// ...
}
Реализация этого интерфейса может использовать механизмы symfony для выполнения фактического перенаправления, и ваша библиотека не зависит от какой-либо реализации.
Возможной реализацией может быть:
class SimpleRedirector implements Redirector {
public function redirect($location, $code) {
header('Location: ' . $location, true, $code);
die();
}
}
Полностью согласен с SirDarius. Это простой дизайн по контракту (DbC). Ваш компонент объявляет интерфейс, которое любое приложение может реализовать по-своему.
Я думал о том, как реализовать его symfony. Обычный простой способ перенаправления PHP в PHP довольно прост. Но чистая реализация Symfony сложнее, поскольку действие контроллера должно возвращать объект ответа и не может просто умереть, потому что ядро должно завершиться. В этом случае Redirector является службой области с запросом на состояние, сохраняя данные перенаправления и предоставляя метод getResponse.
<?php
class RedirectionService implements Redirector {
private $location;
private $code;
public function redirect($location, $code) {
$this->location = $location;
$this->code = $code;
}
public function getResponse() {
$response = new RedirectResponse($this->location, $this->code);
return $response;
}
}
// ...
public function someAction() {
// defined in services.yml and gets our service injected
$libraryService = $this->get('library_service');
$libraryService->work();
$redirectionService = $this->get('redirection_service');
$response = $redirectionService->getResponse();
return $response;
}