Я использую php + blade и написал простой mvc, и теперь мне интересно, как передать данные для просмотра.
Мой объект ответа содержит заголовок, код состояния и тело (представление). Можно ли передавать данные в раздел тела ответа рядом с представлением?->setBody(['view'=>'result','somedata'=>$somedata]);
или объект ответа должен иметь код состояния, заголовок, тело (представление) и данные отдельно от тела (представления)?
теперь в контроллере у меня есть:
return Response::create()
->setStatusCode(200)
->setHeader(['Content-Type' => 'text/html'])
->setBody(['view'=>'result']);
мой класс ответа:
class response implements ResponseInterface
{
protected $statusCode;
protected $headers;
protected $body=[];
public function setStatusCode(string $code) :object
{
$this->statusCode = $code;
return $this;
}
public function setHeader(array $header):object
{
$this->headers=$header;
return $this;
}
public function setBody(array $body): object
{
$this->body = $body;
return $this;
}
public function getStatusCode():string
{
return $this->statusCode;
}
public function getHeaders():array
{
return $this->headers;
}
public function getBody():array
{
return $this->body;
}
public static function create(string $statusCode = null, array $headers = null, string $body = null): response
{
return new Response($statusCode, $headers, $body);
}
public function send(): void
{
foreach ($this->headers as $header => $value) {
header(strtoupper($header).': '.$value);
}
if ($this->headers['Content-Type']== = "text/html" && $this->statusCode === "200") {
View::renderTemplate($this->body['view']);
}
}
}
я могу передавать такие данные, добавляя переменную fx datatable в контроллеры, и это работает:
return Response::create()
->setStatusCode(200)
->setHeader(['Content-Type' => 'text/html'])
->setBody(['view'=>'result','datatable'=>$datatable]);
а затем необходимо настроить действие отправки ответа на:
public function send(): void
{
foreach ($this->headers as $header => $value) {
header(strtoupper($header).': '.$value);
}
if ($this->headers['Content-Type']== = "text/html" && $this->statusCode === "200") {
View::renderTemplate($this->body['view'],'datatable'=>$this->body['datatable']);
}
}
Экземпляр Response не должен нести ответственность за создание объекта Response. Эта задача должна выполняться Фабрика ответов. Пример:
class ResponseFactory extends MessageFactory implements ResponseFactoryInterface {
//...
public function createResponse(int $code = 200, string $reasonPhrase = ''): ResponseInterface {
return new Response($this->body, $code, $reasonPhrase, $this->headers, $this->protocolVersion);
}
//...
}
Экземпляр Response не должен отвечать за отправку заголовков ответа HTTP. Эта задача, наряду с выводом содержимого тела ответа на экран, должна выполняться Излучатель ответа. Пример:
class ResponseEmitter implements ResponseEmitterInterface {
//...
public function emit(ResponseInterface $response): void {
$this
->checkHeadersSent()
->sendStatusLine($response)
->sendResponseHeaders($response)
->outputBody($response)
;
exit();
}
//...
}
Экземпляр Response не должен отвечать за отрисовку файлов шаблонов (также известных как взгляды). Таким образом, его не следует связывать с каким-либо модулем визуализации шаблонов или экземпляром View
для визуализации файлов шаблонов. Задача рендеринга файлов шаблонов должна выполняться визуализатор/движок шаблонов. Пример:
class TemplateRenderer extends BaseTemplateRenderer implements TemplateRendererInterface {
//...
public function render(string $templateName, array $context = []): string {
$templateFile = $this->templatesPath . $this->buildTemplateName($templateName);
$this
->validateTemplateFile($templateFile)
->saveContextValuesToContextCollection($context)
;
return $this->renderTemplateFile($templateFile);
}
private function renderTemplateFile(string $filename): string {
ob_start();
extract($this->contextCollection->all());
require $filename;
$content = ob_get_contents();
ob_end_clean();
return $content;
}
//...
}
Визуализированный контент (нить!) Затем передается в тело экземпляра Response.
Вот пример класса, метод которого addUser
отвечает за рендеринг данного файла шаблона, создание экземпляра ответа, запись отображаемого содержимого в тело ответа и возврат ответа.
/**
* A view to handle the users.
*/
class Users extends Primary {
//...
/**
* Add a user.
*
* @return ResponseInterface The response to the current request.
*/
public function addUser(): ResponseInterface {
$bodyContent = $this->templateRenderer->render('@Templates/Users/Users.html.twig', [
'activeNavItem' => 'Users',
'message' => 'User successfully added',
'users' => $this->getAllUsers(),
]);
$response = $this->responseFactory->createResponse();
$response->getBody()->write($bodyContent);
return $response;
}
//...
}
Ответ, возвращенный Users:addUser
, далее обрабатывается эмиттером ответа. Содержимое его тела, наконец, выводится на экран.
// Create a request.
$request = $container->get('request');
// Create a middleware queue.
$middlewareQueue = $container->get('middleware-queue');
// Handle the request and produce a response.
$response = $middlewareQueue->handle($request);
// Emit the response.
$responseEmitter = $container->get('response-emitter');
$responseEmitter->emit($response);
Итак, в вашем случае ответ можно упростить до следующего. В ваших силах разработать остальные компоненты — те, что я упомянул выше.
class Response implements ResponseInterface {
public function getStatusCode(): int {
//...
}
public function setStatusCode(int $code): static {
//...
}
public function getHeaders(): array {
//...
}
public function setHeader(array $header): static {
//...
}
public function getBody(): string {
//...
}
public function setBody(string $content): static {
//...
}
}
Примечание: Если вы используете return $this;
в методе, используйте static
вместо object
в качестве возвращаемого типа данных.
Если можно, я бы предложил вам разработать приложение на основе MVC, которое использует внешние библиотеки для своих компонентов. Например, вместо того, чтобы разрабатывать собственную реализацию HTTP-сообщения (запрос, ответ, URI, загруженные файлы и т. д.), что займет у вас очень много времени!, я бы рекомендовал использовать пакет Ламинас Диакторос. Или использовать Веточка в качестве механизма шаблонов и средства визуализации для вашего приложения. И так далее.
Примечание: Кстати, метод оказывать шаблонизатора Twig даст вам ответ на ваш вопрос (Можно ли передавать данные в раздел тела ответа рядом с представлением?).
Кроме того, для ваших PHP-приложений, если вы еще этого не сделали, я бы посоветовал следовать Рекомендации по стандартам PHP.
Спасибо, я посмотрю насчет фабрики и эмиттеров. это простой проект, который я написал для изучения php, поэтому я новичок. Я некоторое время изучил laravel и вернулся к чистому php, чтобы узнать, что именно происходит за кулисами приложения - чтобы понять ответы, запросы и прочее :) спасибо за ваше время.