定制 brnc/psr7-symfony1-adapter 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

brnc/psr7-symfony1-adapter

Composer 安装命令:

composer require brnc/psr7-symfony1-adapter

包简介

Partial PSR-7 Adapters for Symfony 1.5

README 文档

README

To enable the use of future-proof PSR-15 middlewares via partial PSR-7 adapters.

Quickstart

// not fully PSR-7 compliant lazy adapters
$serverRequestAdapter = \brnc\Symfony1\Message\Adapter\Request::fromSfWebRequest($sfWebRequest);
$responseAdapter      = \brnc\Symfony1\Message\Adapter\Response::fromSfWebResponse($sfWebResponse);

ServerRequest

Please mind the following PSR-7 violation which is enabled by default:

No immutability by default

as this is just an adapter for \sfWebRequest which cannot easily be replaced with another instance.

This adapter – by default – also returns the very same instance when calling with*() methods. For the same reason calls to methods which cannot act on and alter the underlying \sfWebRequest will throw an \brnc\Symfony1\Message\Exception\LogicException.

This default behaviour can be changed by creating the Request using the Request::OPTION_IMMUTABLE_VIOLATION option set to false. The Request-adapter will then always return new instances when with*()-methods are called and won't throw exceptions on calls which cannot transparently act on the \sfWebRequest- object.

use brnc\Symfony1\Message\Adapter\Request;

$serverRequestAdapter = Request::fromSfWebRequest(
    $sfWebRequest,
    [
        // If set to true a stream on php://input is used instead of creating one over sfWebRequest::getContent() → defaults to false
        Request::OPTION_BODY_USE_STREAM     => false,
        // sfWebRequest-compatibility mode – set to false if you need PSR-7's immutability
        Request::OPTION_IMMUTABLE_VIOLATION => true, 
    ]
);

Response

Please mind the default to mutability!

use brnc\Symfony1\Message\Adapter\Response;

$responseAdapter = Response::fromSfWebResponse(
    $sfWebResponse,
    [Response::OPTION_IMMUTABLE_VIOLATION => false]
);
$newInstance     = $responseAdapter->withBody(
    \GuzzleHttp\Psr7\Utils::streamFor(
        '<html><head><title>Hello World!</title></head><body><h1>PSR-7 Adapters!</h1></body></html>'
    )
);
$newestInstance  = $newInstance->withBody(
    \GuzzleHttp\Psr7\Utils::streamFor(
        '<html><head><body><h1>dead end</h1></body></html>'
    )
);

// selects the content of $newInstance to be send instead of the most recent instance's one (i.e. $newestInstance)
$newInstance->preSend();
// N.b. The stream of $newestInstance is still held in memory until $responseAdapter and all copies got destroyed!
//      This might change in the future when this will be refactored to use WeakMap.

$sfWebResponse->send();

Pass it down to a PSR-15 sub-stack

You may use the ResponseFactory implementing \Psr\Http\Message\ResponseFactoryInterface in order to "spawn" responses within your PSR-15 sub-stack.

$request         = \brnc\Symfony1\Message\Adapter\Request::fromSfWebRequest($sfWebRequest);
$responseFactory = new \brnc\Symfony1\Message\Factory\ResponseFactory($sfWebResponse);
// (dependency) inject the ResponseFactory to your dispatcher, middlewares, and handlers
$entryPoint      = new YourPSR15Dispatcher($responseFactory);
// Dispatch your sub-stack via PSR-15
$response        = $entryPoint->handler($response);
// As $response will be linked to $sfWebResponse you don't need to do anything
// if you are in the context of a Symfony1 action. Only call $response->getSfWebResponse() in dire need!

Manually transcribe a PSR-7 Response to Symfony1

Assume you couldn't use other means, and you're confronted with an arbitrary PSR-7 response you can use the ResponseTranscriptor to copy the data from your PSR-7 response to your \sfWebResponse.

The ResponseTranscriptor by default uses NoCookieTranscriptor, which fails hard in the presence of Set-Cookie' headers. Incorporating (present-day) Cookies into the \sfWebResponse is not strait-forward. However, you are free to implement your own Cookie-Handler implementing CookieTranscriptorInterface and pass it as an optional constructor argument.

// Given arbitrary PSR-7 response…
$psr7response = $psr7responseFactory();
// …use the ResponseTranscriptor in order to–
$transcriptor = new \brnc\Symfony1\Message\Transcriptor\ResponseTranscriptor();
// copy the response's contents.
//   The returned object will be the same as in the argument!
$sfWebResponse = $transcriptor->transcribe($psr7response, $sfWebResponse);

Implemented CookieTranscriptorInterfaces

There are a few CookieTranscriptors already implemented; each come with their specific compromises.

CookieHeaderTranscriptor

Transcribes Set-Cookie headers from your PSR-7 response, into the cookie management of the Symfony1 response. This comes with all downsides of the legacy signature of setrawcookie(). Foremost it's not supporting SameSite-attribute, nor everything else being extension-av as of RFC 265.

AbstractCookieDispatchTranscriptor

The (abstract) CookieDispatchTranscriptor uses reflection and swaps the response's EventDispatcher against a new one. It is very tied against the original implementation of sfWebResponse::sendHttpHeaders especially its logging mechanism via events. The CookieDispatcher puts itself between sfWebResponse and the original sfEventDispatcher, and fires the cookies from the PSR-7 response right before Symfony1 would have sent theirs. You need to implement AbstractCookieDispatchTranscriptor's transcribeCookies() method, depending on your source for the cookies being set. E.g. if your using a 3rd party library. Your code eventually needs to return CookieContainerInterface full of CookieInterfaces. There is already a HeaderCookie, that uses header() and expects an already crafted and complete Set-Cookie-headerline. There are also SetCookie and SetRawCookie which will use the respective methods with the new signature – i.e. three arguments, with the options-array as a third one.

Pass it down to http-foundation i.e. present-day Symfony

Combine this PSR7-Symfony1 Adapter and symfony/psr-http-message-bridge to connect your Symfony1 stack via PSR-7 to symfony/http-foundation objects and leverage using embedded (present-day) Symfony components.

// Use this chain to create a http-foundation request from a Symfony1's \sfWebRequest
$psrRequest            = \brnc\Symfony1\Message\Adapter\Request::fromSfWebRequest($sfWebRequest);
$httpFoundationFactory = \Symfony\Bridge\PsrHttpMessage\Factory\HttpFoundationFactory();
$symfonyRequest        = $httpFoundationFactory->createRequest($psrRequest);

// Handle the request with some present day Symfony component
$symfonyResponse = $httpKernel->handle($symfonyRequest);

// Possibly ResponseFactory is best created in the Symfony1 context
$responseFactory = new \brnc\Symfony1\Message\Factory\ResponseFactory($sfWebResponse);

// Obtain other PSR17 factories,
//   while only ResponseFactory & StreamFactory will be used (as of today)
$streamFactory   = \brnc\Symfony1\Message\Factory\GuzzleStreamFactory();
$decoyFactory    = \brnc\Symfony1\Message\Factory\DecoyHttpFactory();
// Construct the PsrHttpFactory from symfony/psr-http-message-bridge and translate…
$psrHttpFactory  = Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory(
    $decoyFactory, $streamFactory, $decoyFactory, $responseFactory
);
$psrResponse     = $psrHttpFactory->createResponse($symfonyResponse);
// As $psrResponse will be linked to $sfWebResponse as it was created through the
// ResponseFactory you don't need to do anything if you exit via an Symfony1 action.
// Only call $psrResponse->getSfWebResponse() in dire need!

brnc/psr7-symfony1-adapter 适用场景与选型建议

brnc/psr7-symfony1-adapter 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 34.58k 次下载、GitHub Stars 达 3, 最近一次更新时间为 2018 年 12 月 01 日, 在 PHP 生态内属于活跃度较高的组件。

它主要适用于以下技术方向: 「http」 「message」 「symfony1」 「psr-7」 「http-message」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。

我们在过去多个企业项目中使用过 brnc/psr7-symfony1-adapter 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。

围绕 brnc/psr7-symfony1-adapter 我们能提供哪些服务?
定制开发 / 二次开发

基于 brnc/psr7-symfony1-adapter 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。

BUG 修复 & 性能优化

线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。

项目外包 & 长期维护

承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。

yvsm@zunyunkeji.com QQ:316430983 微信:yvsm316 西安尊云信息科技 · 专注 PHP / Go / 分布式系统研发

统计信息

  • 总下载量: 34.58k
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 3
  • 点击次数: 16
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 3
  • Watchers: 0
  • Forks: 1
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2018-12-01