Well, since I don't think this will be solved here, I went ahead and made 
my own PSRs.  I realize that changing the standard is quite troublesome, 
and that it's nice to be able to test the waters prior to committing.  So, 
I present the following

My revision of PSR 7, so that PSR 7 classes come with built in factories
https://github.com/PHP-SG/psr-100

My implementation of PSR 100, using Nyholm/psr7 
<https://github.com/Nyholm/psr7> as a base
https://github.com/PHP-SG/psr-100-implementation

My server implementation of PSR 100, using Nyholm/psr7-server 
<https://github.com/Nyholm/psr7-server> as a base
https://github.com/PHP-SG/psr-100-server

And, my revision of PSR 15, creating something I call AppInterface
https://github.com/PHP-SG/psr-101

Feedback is welcome.






On Wednesday, July 7, 2021 at 5:02:39 PM UTC-7 Adam Frederick wrote:

> To go further down my path of the last sentence of the last paragraph, you 
> could say that each of these factory outputs are themselves factories.  By 
> returning a new instance of itself when you do something like "withHost()" 
> , Psr\Http\Message\UriInterface is a factory for itself.  And, another way 
> to resolve the non-standardized access to PSR 17 factories is to add the 
> factory methods to each of the factory outputs.  A UriInterface would have 
> a `create` method that had the same input as the factory `createUri()`.  
> Again, regarding separation of concerns, the creation of itself is in the 
> concern of the object already by it's need to create copies through its 
> other methods.
> The only problem I can see with this, from a concern perspective, is 
> perhaps the StreamInterface.  Why would a file stream know how to make a 
> string stream?  However, in implementation, this is rather trivial.  I 
> imagine you have some `class GeneralStream{}`  `class FileStream extends 
> GeneralStream`, and GeneralStream would have `->createFromFile`, 
> `->create`, `->createFromResource` which FileStream would inherit.
>
> On Wednesday, July 7, 2021 at 11:42:54 AM UTC-7 Adam Frederick wrote:
>
>> That makes a HUGE assumption, however, that the message instance knows 
>>> exactly how to construct the stream instance composed into it.
>>>
>>> Let me give some examples. In Diactoros, we have several stream types:
>>>
>>> - CallbackStream expects a single constructor argument, a callable.
>>> - PhpInputStream expects a single constructor argument, a resource.
>>> - RelativeStream expects two arguments, a StreamInterface to decorate, 
>>> and an integer offset
>>> - Our primary Stream implementation has two arguments, a resource or 
>>> string representing the resource to create (e.g., "php://memory"), and a 
>>> filesystem mode (e.g., 'r', 'a+', 'rw', etc.)
>>>
>>
>> Right, but in general, the concern of withBodyString() can be covered by 
>> some default stream that implements the interface.
>>  
>>
>>> We actually had a number of discussions about this in the PSR-17 WG, and 
>>> even considered adding some combinations to the http-factory-util package, 
>>> but there were soooo many variants, and we were concerned people would 
>>> typehint on the intersection interfaces in the util package instead of the 
>>> ones defined in the spec, which would hamper interop.
>>>
>>
>> I agree, the countless combinations is not a good idea.  That is why I 
>> recommend a full combo only, and I don't see that as being restrictively 
>> un-optimized. 
>>  
>>
>>>
>>> It may be time to revisit that, as I think a few of these have come up 
>>> as "generally useful":
>>>
>>> - ResponseFactoryInterface&StreamFactoryInterface (per the above)
>>> - RequestFactoryInterface&UriFactoryInterface&StreamFactoryInterface
>>> - 
>>> ServerRequestFactoryInterface&UriFactoryInterface&StreamFactoryInterface&UploadedFileFactoryInterface
>>> - and one combining all of them (e.g., the one from Nyholm/psr7)
>>>
>>> That could happen either as an errata/addendum to PSR-17, or a separate 
>>> spec.
>>>
>>
>> Yes, these are individually useful, but I don't see there being an 
>> adequate optimization need to make subsets instead of a full set.
>>  
>>
>>> What are you suggesting, exactly? That we add an example demonstrating 
>>> this (using constructor injection to provide PSR-17 factories within PSR-15 
>>> implementations for purposes of creating PSR-7 instances) to the metadoc 
>>> for PSR-15? Or documentation detailing how you resolve the interface 
>>> typehint to an implementation? Or something else?
>>>
>>
>> Initially I was suggesting that you make it part of a standard that 
>> implementors of middleware must provide IoC DI to the middleware 
>> constructor.  But, this appears to be outside the scope of the standard (it 
>> would be dealing with how frameworks deal with middleware construction)
>>  
>>
>>> This is exactly what PSR-17 suggests, though! It exists to allow 
>>> typehinting in your constructors against the PSR-17 factories in your 
>>> classes so as to prevent directly instantiating a concrete PSR-7 
>>> implementation. How the framework does that is really up to the framework. 
>>> But this was the intent of PSR-17, and it is spelled out clearly in section 
>>> 2 of its metadoc.
>>>
>>
>> Right, and I was suggesting making it a standard that the framework must 
>> uphold IoC DI for middleware construction.  This would require both an 
>> addendum to defining middleware ( to say factories are injected ), and a 
>> PSR that tells frameworks to inject factories.
>>  
>>
>>> Your middleware packages should depend on and typehint against PSR-7, 
>>> PSR-15, and PSR-17, versus specific implementations. If you typehint 
>>> against those, there are certain guarantees provided for you; most salient 
>>> to your concerns is the fact that PSR-17's stream factory interface 
>>> specifically only addresses resource and file-backed streams, which means 
>>> that you can depend on them to (a) be empty, and (b) be writable. As such, 
>>> writing your middleware to target the PSR-17 interfaces as constructor 
>>> dependencies gives you the interop you're looking for.
>>>
>>
>> Right, but I was considering what is perhaps a non issue.  I was 
>> considering making middleware for a framework which did not do IoC DI.  
>> And, again, my issue is, if IoC DI is the de facto standard, why not make 
>> it the actual standard.
>>  
>>
>>> Again, that is the specific, stated goal of PSR-17, that you inject the 
>>> factories in your middleware in order to produce PSR-7 artifacts.
>>>  
>>>
>>>> But, I think an easier mechanism would be to have an 
>>>> extended RequestHandlerInterface that implements the factories.  "PSR 21 
>>>> ExtendedRequestHandlerInterface implements ...."
>>>>
>>>
>>> This violates the separation of concerns principle, and introduces new 
>>> questions:
>>>
>>> - How does the handler know how to create these artifacts?
>>>
>> There's actually two considerations here.
>> 1. Since both the response and request objects already know how to create 
>> new objects of their class by modification of themselves, it is within 
>> their realm of concern to create blank objects.  Since these objects are 
>> not merely containers (since you can directly modify the content of the 
>> headers), it should be expectable that the normal structure of the response 
>> can be modified by these objects without additional tools.
>> 2. Since the request handler must return a response, it should know how 
>> to return a response - it is within the realm of concern to be able to do 
>> this.
>>
>>> - What PSR-7 implementation will the handler use?
>>>
>> This shouldn't matter since it uses an interface.  If the middleware 
>> requires a specific implementation, that is different than what the 
>> framework is giving, it would require it as a dependency.
>>
>>> - Or is it composing PSR-17 instances to do the work? If so, how does it 
>>> get access to those? And if it's composing them... why not just call on 
>>> those factories directly instead of proxying to them?
>>>
>> Access to those would either be through the handler, or through the 
>> request and response objects.
>> Calling the factories directly, either through DI or require/autoload has 
>> downsides.
>>
>> For example, with IoC DI, apart from the issue with making the assumption 
>> the framework will provide IoC DI, I could have middleware that has 
>> configuration parameters like
>>
>> class Middleware implements \Psr\Http\Server\MiddlewareInterface{
>> public function __construct(ResponseFactoryInterface $responseFactory, 
>> ServerRequestFactoryInterface $ServerRequestFactory, UriFactoryInterface 
>> $uriFactory, $config_param1, $config_param2)
>> public function process(ServerRequestInterface $request, 
>> RequestHandlerInterface $handler): ResponseInterface {}
>> }
>> The problem with this being, prior to presenting this middleware to the 
>> framework, you have 3 factory requirements you must resolve prior to adding 
>> your own configuration parameters.  (I mentioned how you can still do this 
>> with DI IoC with the framework in discord, so it is just an inconvenience)
>>
>>>
>>> Your second example actually raises more questions for me (see above). 
>>> (Some call this style "spooky magic from a distance" as it looks 
>>> convenient, but when you dig, you get a lot of questions about how things 
>>> actually work, and how you can modify them.)
>>>
>>
>> I actually think this is the most obvious part.  The framework chooses 
>> its own factory default implementations.
>>  
>>
>>> The first (using DI) is something a framework should cover in its 
>>> initial tutorials. In some frameworks, reflection-based DI will resolve 
>>> them for you. In others, you will provide configuration detailing which 
>>> implementation the DI container should use. Others will have you create and 
>>> wire in a factory that will handle this detail (and this is where PSR-11 
>>> comes into play, as the factory can then retrieve instances from the 
>>> container to resolve dependencies).
>>>
>>> The point, however, is that:
>>>
>>> - Your middleware is decoupled from a specific framework or PSR-7/PSR-17 
>>> implementation. This allows both composition into different frameworks, as 
>>> well as substitution for its own dependencies.
>>>
>> Again, it is coupled to frameworks that use IoC DI.  However, I think I 
>> will stop pointing this out since, as said elsewhere, it is "de facto 
>> standard" and no one seems to want to standardize it to make it de jure
>>  
>>
>>> - The code is declarative: you know what you need to provide it in order 
>>> to create an instance. This makes it testable and self-documenting. Your 
>>> users can find the PSR-7/PSR-17 combination that works for them and 
>>> directly instantiate the class using concrete implementations.
>>>
>> I can't think of a case needing a specialized testing PSR7 or PSR17 
>> implementation.  If there were such a case, I imagine the frameworks would 
>> allow adjusting the default factories used by the request handler
>>  
>>
>>> Am I understanding correctly that you're concerned with the "how do I 
>>> get my PSR-17 instances to my middleware" question? Particularly so that 
>>> your middleware can operate with multiple frameworks?
>>>
>>
>> Not entirely.  I want my middleware to work on _all_ frameworks that meet 
>> the standards.  As such, the activities which are within the realm of 
>> concerns of the middleware, specifically modifying the response or request, 
>> should be standardized, and that standard should mean all frameworks that 
>> comply with the standard can run my middleware.  
>>
>> Perhaps the issue here is the application of separation of concerns. The 
>> factories are correctly separate as interfaces for their individual 
>> concerns.  But the concern of the request handler is all of the factories, 
>> b/c the concern of the request handler is both the request and the 
>> response.  Or, taken a different way, the concern of the response object is 
>> everything related to changing and viewing the response (all associated 
>> factories), and the concern of the request is everything related to 
>> changing and viewing the request (all associated factories).
>>
>>  
>>
>

-- 
You received this message because you are subscribed to the Google Groups "PHP 
Framework Interoperability Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to php-fig+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/php-fig/05ea388d-be89-4bba-9c40-65cc311a65ean%40googlegroups.com.

Reply via email to