Please excuse my naivete, but upon making PSR 15 classes, I noticed an issue which I have not found satisfactorily resolved online or in this discussion group.The idea behind interoperability is to make sure things work on different systems. Part of doing this is making sure there is a standard interface for normal activity. Part of normal activity of a middleware would be altering the response body. But, this presents a problem, since there is no standard method for going about creating a new stream within middleware.What is the standard for accessing a Psr\Http\Message\StreamInterface implementation from within middleware?- if I want to modify the body, I have to make a new stream (seeking and writing will often not fit)I would suggest, given the commonallity of not caring about streams in some middleware, the response gains two functions:1. "withBodyString()"2. possibly "getBodyString()" for expectation (just does __toString())
Further, I would suggest two combined things for middleware:1. ServerRequestInterface should also implement all the PSR 17 interfaces. Thus, middleware would access a factory like `$handler->createResponse()`. This itself, the extended interface implementation, could be a PSR.
2. Middleware constructor interface dependencies should be resolved, allowing injection of factories.Combined, the ServerRequestInterface could just inject itself wherever a PSR 17 factory was required. However, #2 puts the demand of interface dependency injection the the implementer.
Without a standard, constructing middleware relies on knowing what the framework will do. If the assumption is that middleware will have the factories injected, this should be stated in the standard as the standard.
specifically NOT force the idea that content MUST be a string
We deliberately chose not to have any of the PSR-17 interfaces extend from the others. The reason is that there were too many combinations, and most times, you only need 1, 2, or 3 capabilities, making it relatively easy to compose them into your classes via dependency injection. If you find yourself needing multiple capabilities regularly, create your own interface that extends the set of interfaces you use regularly, and type-hint on that in your middleware or handlers.
2. Middleware constructor interface dependencies should be resolved, allowing injection of factories.Combined, the ServerRequestInterface could just inject itself wherever a PSR 17 factory was required. However, #2 puts the demand of interface dependency injection the the implementer.Constructors cannot be specified in interfaces. Well, they can, but PHP does not require implementations to honor them.
But the fact that PHP won't do it, and it would preclude having custom constructors, means it's simply not an option.Without a standard, constructing middleware relies on knowing what the framework will do. If the assumption is that middleware will have the factories injected, this should be stated in the standard as the standard.There are no assumptions.You can instantiate a response, URI, stream, etc. directly in your middleware. (and thus tie yourself to a specific implementation)Or you could inject factories, and use the factories to create the instances.It's up to you as a developer to define what your class needs to do its work. PSR-7, PSR-15, and PSR-17 are very loosely coupled to allow exactly this.
specifically NOT force the idea that content MUST be a stringWhat I presented is not advocating forcing the idea that body must be a string. In most cases, it is a string of text, and in all cases, it can be a string (although not very useful to have a binary stream turned in to a string - but who would do that). I would imagine most HTTP middleware in php is dealing with bodies as strings. You did make a good point on discord, however, that `withBodyString()` would force the response object to know how to create a stream from the string. I don't think this is so problematic, however, since it already knows about the stream and the stream class, It would essentially have to do $class = get_class($body_stream); new $class($string); for the withBodyString function. And yes, the middleware could also do this, but that is not immediately obvious to middleware makers.
We deliberately chose not to have any of the PSR-17 interfaces extend from the others. The reason is that there were too many combinations, and most times, you only need 1, 2, or 3 capabilities, making it relatively easy to compose them into your classes via dependency injection. If you find yourself needing multiple capabilities regularly, create your own interface that extends the set of interfaces you use regularly, and type-hint on that in your middleware or handlers.Right, it can be done. That's not my issue. My issue is that it is not standardized. Again, doing it the way you are mentioning relies on the non-standard that whatever is using my middleware resolves the interface dependency.I agree that it make sense to separate the factories as different interfaces. But implementations will combine them because the separation is unnecessary (https://github.com/Nyholm/psr7/blob/master/src/Factory/Psr17Factory.php)
2. Middleware constructor interface dependencies should be resolved, allowing injection of factories.Combined, the ServerRequestInterface could just inject itself wherever a PSR 17 factory was required. However, #2 puts the demand of interface dependency injection the the implementer.Constructors cannot be specified in interfaces. Well, they can, but PHP does not require implementations to honor them.Not what I meant by "constructor interface dependencies". I meant __construct(RequestFactoryInterface $request){}, where you then rely on injection that resolves the implementation of the interface.
But the fact that PHP won't do it, and it would preclude having custom constructors, means it's simply not an option.Without a standard, constructing middleware relies on knowing what the framework will do. If the assumption is that middleware will have the factories injected, this should be stated in the standard as the standard.There are no assumptions.You can instantiate a response, URI, stream, etc. directly in your middleware. (and thus tie yourself to a specific implementation)Or you could inject factories, and use the factories to create the instances.It's up to you as a developer to define what your class needs to do its work. PSR-7, PSR-15, and PSR-17 are very loosely coupled to allow exactly this.Right, so there are two non-standardized options.1. use dependency injection and rely on the framework injecting the dependencies
2. create my own set of package requirements for my middleware. The problem with this being the potential for there being 20 PSR 17 implementations, and various middleware all requiring their own.
My thoughts on the matter are about allowing the writer of middleware to have a standardized mechanism for accessing PSR 17 factories. If dependency injection should be the standard, then standardize it.
But, I think an easier mechanism would be to have an extended RequestHandlerInterface that implements the factories. "PSR 21 ExtendedRequestHandlerInterface implements ...."
Think about, as a framework, explaining this to middleware developers.You either end up explaining:"in your __constructor, make sure to have the various factory parameters that you need, and then assign them to properties of your object so you can use them in your process method. We will inject the dependencies as you need them."Or you tell them"you can create a stream by doing $handle->createStream()"What ends up creating more standardized code?
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.)
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.
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.
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?
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.
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.
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?
- What PSR-7 implementation will the handler use?
- 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?
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.)
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.
- 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.
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?
Here at PHP-FIG we obviously believe that creating standards is a good thing and in principle no topic relevant to the FIG [mission][1] is taboo.
Establishing standards is however a group effort and the PHP-FIG bylaws specify a [workflow][2] for creating a new PSR.
To summarize the bylaw, the first official stage is to form a working group of interested people and create a proposal for a new PSR. The proposal should explain the problem and the likely approach. Once that proposal has been accepted a PSR number is assigned. The working group can than work on finalizing the proposal to the point that it can be accepted and published.
If you continue this work outside the FIG procedures, we request that you don't claim any affiliation to the PHP-FIG. Specifically, we ask you to not cause confusion to the PHP community at large by representing your proposal as a PSR.
--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/CtluNYS3QxY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to php-fig+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/25a23980-fceb-4470-bbe0-82cf1228c434n%40googlegroups.com.
--
You received this message because you are subscribed to a topic in the Google Groups "PHP Framework Interoperability Group" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/php-fig/CtluNYS3QxY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to php-fig+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/2f548ee2-f939-41a6-b57d-363fa98cc74a%40www.fastmail.com.
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+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/CAPSiWTo%3DUYjj_gpky3gv0NfH%2B%2BhsR-R7WxCTqdFpB1atLg4OQg%40mail.gmail.com.
I have read through some of this long discussion, and in essence, I agree with Larry thay using “PSR” in the PHP community for a standard that is not a FIG standard is harmful to the community and devalues the work of FIG.
We have been around for a long time; when PHP developers see “PSR” they will look it up at FIG, not find it; and get confused. Let’s not confuse our wonderful community.
I’m sorry Adam that you felt that the communication was patronizing. That is perhaps something that we can look into.
Adam,I know I don't chime in much here on the message boards, but I wanted to drop in and say hello, not necessarily in an official capacity but just as a developer in the community who's been a long-time follower of the FIG and the PSR standards.I very much understand the feeling of being up against a monolithic entity where it seems hard to get a word in edgewise or get your foot in the door. A lot of us feel this way when contributing to projects larger than our own, and for me personally, the fear of getting a negative response is what has kept me from submitting many contributions upstream to the projects my own software depends on. That feeling is real and valid, and it's imperative for the larger institutions to do what they can to remain approachable despite their size and momentum.In that context, there's nothing at all wrong with submitting ideas to the group here. Your ideas aren't without precedent, either, since I've seen numerous implementers of the PSR standards lump them together into singular libraries that cover multiple standards at once or extend the standards to be easier to use in their own context. By all accounts, even if your repositories didn't wind up as FIG standards themselves, they could continue to exist as standalone code and would likely be useful to a number of people looking to implement the combined standards in a friendly way.I also agree with Michelle in that it is unfortunate you were met with a response that you felt patronized your contributions. It's important that any interactions with participants in the FIG process be respectful and professional.
By that same token, however, I'm not sure that messages like:> Larry, if two others here would second and third your opinion, I will explain why you are wrong.
...convey that level of respectfulness or professionalism either.
I think the friction you're feeling with the FIG group doesn't stem from the content of your suggestions themselves, but rather the manner in which you presented them, which was in the form of a GitHub organization named "PHP-SG" with standards that presented as numbered "PSR"s.
What does "PHP-SG" stand for? Absent any clarifying information on my side, and given the organization's only contents are these new "PSR" standards, I'd have to assume it stands for something like "PHP Standards Group".
Surely you see the reason for any pushback you're feeling here.
I know your response thus far has been that the phrase "PSR" is a generic one and that your own "PSRs" aren't popular enough from an SEO perspective to compete with the official ones. To the second point, I think most of the folks here would argue that it isn't your project's relative popularity that is the problem, but rather the precedent that is set when anyone who proposes an idea to the PHP-FIG spins up their own organization, creates repositories and assigns their own FIG numbers to their own code. This would be an immensely confusing mess in very short order, and would leave a hundred repositories scattered across GitHub at varying stages of completion or stability that are all named "PSR-something".
Even if developers weren't likely to find those repositories first, the idea that they would find them at all, and then associate them with the same process that the existing PSRs they're familiar with have gone through, is cause for concern.
To your point that the phrase "PSR" is generic, I would be inclined to agree if there was any prior art whatsoever that suggested that was the case.
If you ask people from all around the PHP community what a PSR is, I would wager that all of the ones who know the term would direct you to one of the PHP-FIG standards.
The PHP core team uses a different name for their own proposals, and none of the popular frameworks out there (even the ones who don't necessarily adhere to the PSR standards) have made their own standards and called them "PSRs". This is basically a first, so that's why you're seeing such a strong pushback on the concept, because nobody involved wants to set the precedent that you can make your own PSRs when submitting ideas to the FIG, or in general.
So, really the long and short of it here is it's all in the naming. If you can understand where the FIG is coming from in that regard, then we may be able to move forward in a productive way.
I'll add my opinion in with Larry's to get closer to the requisite threshold where you tell FIG, which has gotten buy-in from various maintainers to use the same interfaces, just how wrong they are. While grabbing a namespace on GitHub purporting to be, well, more than yourself.
Hopefully you can understand the consternation arising when you decide to skip that step after framework/middleware maintainers reply "yes, we thought of that, and here's why we didn't go down that route."
With that in mind, which two frameworks do you intend to individually convince to accept a PR exhibiting the functionality you're championing?
--
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+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/php-fig/0b42760e-4fc9-4223-b546-51f8d03776bbn%40googlegroups.com.
You're posting to the FIG list, so you telling Larry, Buster, myself and others why we are mistaken has the side effect of also telling FIG.
Given that you believe that Laravel and Symfony could make use of your spec, it's worth approaching those maintainers directly, as neither are members of FIG.
If you're clear about your goal here (e.g. framework adoption within X timeframe), there may be better ways of achieving that goal than posting to the list.
- you answered to Larry patronizing him (supposedly in retaliation), without dignifying him of a proper response (the "Larry, if two others here would second and third your opinion, I will explain why you are wrong." answer)
- you claimed multiple times that you were busy building stuff, hence valuing your time, but you dismissed others when they weren't able to respond to you in a timely fashion, hence not valuing theirs
- you rudely accused PHP-FIG members of lying and being ignorant just because they were disagreeing with you
- you ignored and dismissed multiple accounts from multiple people discouraging you to use the "Standards Group" and "PSR" names
- you dismissed the possible implications of such course of action, which I consider not taking any responsibility for your actions
On this last two points, I would like to remind you that "PHP Standards Group" was the original name of the PHP-FIG, and the founders abandoned it just because of the sheer amount of backslash from the PHP community at large; so that TWO different reasons to not use this name;
so I, again, encourage you to not use those names, to avoid confusing users, but instead to have a name to call your own, if you really want to push your ideas outside of the PHP-FIG. I hope you can reconsider that in a show of good faith, so that we can go on and start discussing on technical merits only from this point further.