On Saturday, May 13, 2017 at 12:31:20 PM UTC-5, Woody Gilk wrote:
>
> On Sat, May 13, 2017 at 12:12 PM, Rasmus Schultz <[email protected] 
> <javascript:>> wrote:
>
>> What do you mean by "middleware that does not return a response"?
>>
>
> Ultimately it will. In PSR-15 this is done via delegate. My question is 
> more about how the interfaces proposed by David would do this delegation. 
> Right now I don't see how it would be possible without passing a factory to 
> a middleware, which (I thought) he was attempting to avoid.
>

I don't think that was what he was attempting to avoid. I think his was an 
attempt to solve the DI problem (the thing I care about) while still not 
having to pass the delegate to every middleware handle/__invoke call (I 
believe the idea that Rasmus is exploring). From what I see, this is done 
by injecting a factory concept into the workflow.

The factory would receive the next/delegate at runtime and could thus be 
instantiated by an autowiring DI container upfront without any problems.

It still requires the individual middleware & factory combo to have a way 
to ensure that the middleware instance stores the next/delegate prior to 
being invoked. Which means, most likely, that the middleware themselves 
cannot be autowired and *must* be created manually by the factory.

In my mind, it moves the magic around in a way that is slightly more 
automated (meaning, I'd only be able to whine about DI concerns at a 
fraction of the volume of before because the *middleware factory* can still 
be autowired...) at the expense of adding an explicit factory to the 
workflow of every middleware.

While I think this is a great way to move the discussion forward, I'm not 
happy about the idea that every middleware is going to effectively require 
two classes be written. I would guess that most factories are going to end 
up being proxies and will have all of the dependencies of the original 
middleware just to pass them on via constructor injection.

Here is what this would look like using an actual middleware I've used in 
the past. I've kept the delegate naming for now just to show what we're 
actually talking about here in practical terms.

BEFORE

class UserIdMetadataEnrichment implements MiddlewareInterface
{
    private $metadataEnricherChain;
    private $userIdentityMapper;

    public function __construct(
        MetadataEnricherChain $metadataEnricherChain,
        UserIdentityMapper $userIdentityMapper
    )
    {
        $this->metadataEnricherChain = $metadataEnricherChain;
        $this->userIdentityMapper = $userIdentityMapper;
    }

    public function __invoke(RequestInterface $request, DelegateInterface 
$delegate)
    {
        // ... do stuff

    }
}



AFTER

class UserIdMetadataEnrichmentFactory implements MiddlewareFactoryInterface
{
    private $metadataEnricherChain;
    private $userIdentityMapper;

    public function __construct(
        MetadataEnricherChain $metadataEnricherChain,
        UserIdentityMapper $userIdentityMapper
    )
    {
        $this->metadataEnricherChain = $metadataEnricherChain;
        $this->userIdentityMapper = $userIdentityMapper;
    }

    public function createMiddleware(DelegateInterface $delegate)
    {
        return new UserIdMetadataEnrichment(
            $delegate,
            $this->metadataEnricherChain,
            $this->userIdentityMapper
        )
    }
}


class UserIdMetadataEnrichment implements MiddlewareInterface
{
    private $metadataEnricherChain;
    private $userIdentityMapper;
    private $delegate;

    public function __construct(
        DelegateInterface $delegate,
        MetadataEnricherChain $metadataEnricherChain,
        UserIdentityMapper $userIdentityMapper
    )
    {
        $this->metadataEnricherChain = $metadataEnricherChain;
        $this->userIdentityMapper = $userIdentityMapper;
        $this->delegate = $delegate;
    }

    public function __invoke(RequestInterface $request)
    {
        // ... do stuff

    }
}






At the end of the day it comes down to whether the delegate/next of a 
middleware should be a runtime dependency or an instance dependency. I 
think that is the core of what Rasmus is exploring here. It seems like he 
has decided it should not be a runtime dependency. I disagree.

If the same middleware class is used in several points throughout an 
application, why might each individual instance know about the delegate it 
is responsible for? In which situations would this impact how the 
middleware will actually run?

I've neither seen nor written middleware where the same instance mounted 
several places throughout an application did not work as intended and 
expected.


TL;DR?

The original proposal treats the delegate as a runtime dependency along 
with the request in question at that point in time. Rasmus is proposing the 
delegate becomes an instance dependency tying each instance of the 
middleware explicitly to a specific point in the application when it is 
constructed, requiring every instance of a middleware to be instantiated 
individually instead of reusing a shared instance and finding some way to 
get access to the delegate by some other means (constructor or setter 
injection?). David's proposal tries to resolve these two by providing a 
factory that allows a single factory instance to receive the delegate at 
runtime from any point in the application with the intention to create a 
middleware instance on the spot that ties the request and delegate to each 
other at that point in time.

-- 
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 [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/php-fig/e9af0c97-575d-4a76-8e22-01275f7f37a2%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to