PHP MVC 传递数据以响应 object 到 body(视图)?
PHP MVC pass data in response object to body(view)?
我正在使用 php + blade 并编写了简单的 mvc,现在我想知道如何将数据传递给视图。
我的回复 object 包含 header、状态代码和 body(视图)。可以将数据传递到视图旁边的响应 body 部分吗?
->setBody(['view'=>'result','somedata'=>$somedata]);
或响应 object 应具有状态码、header、body(视图)和与 body(视图)分开的数据?
现在在控制器中我有:
return Response::create()
->setStatusCode(200)
->setHeader(['Content-Type' => 'text/html'])
->setBody(['view'=>'result']);
我的回复class:
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 数据表变量,我能够像这样传递数据并且它有效:
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 object。此任务应由 响应工厂 执行。一个例子:
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 响应的响应 headers。此任务连同将响应 body 的内容打印到屏幕,应由 响应发射器 执行。一个例子:
class ResponseEmitter implements ResponseEmitterInterface {
//...
public function emit(ResponseInterface $response): void {
$this
->checkHeadersSent()
->sendStatusLine($response)
->sendResponseHeaders($response)
->outputBody($response)
;
exit();
}
//...
}
模板renderer/engine
Response 实例不应该负责呈现模板文件(也称为 views)。因此,不应将其耦合到任何模板渲染器或 View
实例以渲染模板文件。渲染模板文件的任务应该由模板renderer/engine执行。一个例子:
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;
}
//...
}
呈现的内容(一个字符串!)然后被传递到一个响应实例的body。
例子
这里是一个class的例子,它的方法addUser
负责渲染给定的模板文件,创建一个Response实例,将渲染的内容写入Responsebody并返回响应。
/**
* 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
返回的 Response 由 Response 发射器进一步处理。它的 body 内容最终打印在屏幕上。
// 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);
返回...您的简化回复
因此,对于您的情况,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-based 应用程序,该应用程序的组件使用外部库。例如,与其开发自己的 HTTP 消息实现(请求、响应、URI、上传的文件等)——这会花费你很长时间!我建议使用 Laminas Diactoros package. Or to use Twig 作为模板引擎和您的应用程序的渲染器。等等。
注意:对了,Twig模板引擎的the render method会给你解答你的问题(Is it ok pass数据响应 body 视图旁边的部分?).
此外,对于您的 PHP 应用程序,如果您还没有这样做,我建议您遵循 PHP Standards Recommendations.
资源
- Sandro Mancuso : Crafted Design
- PHP Standards Recommendations(尤其是 1、4、7、11、12、15、17)
- PHP-DI - The dependency injection container for humans
- FastRoute - Fast request router for PHP
- Twig - The flexible, fast, and secure template engine for PHP
- Laminas Diactoros - PSR-7 HTTP 消息接口以及 PSR-17 HTTP 消息工厂接口的实现
- PHP-DI Invoker,调用任何 PHP 可调用的方法,如控制器方法
我正在使用 php + blade 并编写了简单的 mvc,现在我想知道如何将数据传递给视图。
我的回复 object 包含 header、状态代码和 body(视图)。可以将数据传递到视图旁边的响应 body 部分吗?
->setBody(['view'=>'result','somedata'=>$somedata]);
或响应 object 应具有状态码、header、body(视图)和与 body(视图)分开的数据?
现在在控制器中我有:
return Response::create()
->setStatusCode(200)
->setHeader(['Content-Type' => 'text/html'])
->setBody(['view'=>'result']);
我的回复class:
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 数据表变量,我能够像这样传递数据并且它有效:
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 object。此任务应由 响应工厂 执行。一个例子:
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 响应的响应 headers。此任务连同将响应 body 的内容打印到屏幕,应由 响应发射器 执行。一个例子:
class ResponseEmitter implements ResponseEmitterInterface {
//...
public function emit(ResponseInterface $response): void {
$this
->checkHeadersSent()
->sendStatusLine($response)
->sendResponseHeaders($response)
->outputBody($response)
;
exit();
}
//...
}
模板renderer/engine
Response 实例不应该负责呈现模板文件(也称为 views)。因此,不应将其耦合到任何模板渲染器或 View
实例以渲染模板文件。渲染模板文件的任务应该由模板renderer/engine执行。一个例子:
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;
}
//...
}
呈现的内容(一个字符串!)然后被传递到一个响应实例的body。
例子
这里是一个class的例子,它的方法addUser
负责渲染给定的模板文件,创建一个Response实例,将渲染的内容写入Responsebody并返回响应。
/**
* 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
返回的 Response 由 Response 发射器进一步处理。它的 body 内容最终打印在屏幕上。
// 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);
返回...您的简化回复
因此,对于您的情况,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-based 应用程序,该应用程序的组件使用外部库。例如,与其开发自己的 HTTP 消息实现(请求、响应、URI、上传的文件等)——这会花费你很长时间!我建议使用 Laminas Diactoros package. Or to use Twig 作为模板引擎和您的应用程序的渲染器。等等。
注意:对了,Twig模板引擎的the render method会给你解答你的问题(Is it ok pass数据响应 body 视图旁边的部分?).
此外,对于您的 PHP 应用程序,如果您还没有这样做,我建议您遵循 PHP Standards Recommendations.
资源
- Sandro Mancuso : Crafted Design
- PHP Standards Recommendations(尤其是 1、4、7、11、12、15、17)
- PHP-DI - The dependency injection container for humans
- FastRoute - Fast request router for PHP
- Twig - The flexible, fast, and secure template engine for PHP
- Laminas Diactoros - PSR-7 HTTP 消息接口以及 PSR-17 HTTP 消息工厂接口的实现
- PHP-DI Invoker,调用任何 PHP 可调用的方法,如控制器方法