> While I can certainly see the value in the architecture this would imply,
it's by no means the only architecture

I disagree that this implies architecture.

"takes a request and returns a response" is in my opinion the least
opinionated, most open-ended definition you can have of a controller - in
my opinion, it does not imply architecture, at all. You're completely free
to use traits, composition, base-classes, external services, registries,
dependency-injection, middleware - anything you can dream up, the only
requirement is that you ultimately take a PSR-7 request and produce a
response, which, ultimately, if you're using PSR-7, you're going to, one
way or the other.

Are you commenting on the controller-interface itself or are you more
opposed to the idea of going as far as defining filters?

I agree that maybe the filter concept is a bit more opinionated, but this
would of course be optional - that's why it's a separate interface.

> Many controller systems I've seen (including Drupal's, even before
Symfony) used one or another means of automatically extracting information
from the request to pass into the controller; loaded domain objects based
on the URL, for instance

Interestingly, that was our first approach - it's perfectly possible with
this interface signature, and moving from our initial controller base-class
to a new one was painless. We can port one controller at a time from one
strategy to another, because no matter the internal architecture of each
controller, or how we wire them up in our stack, they only ultimately need
to have one thing in common: they take a request and return a response.

> it's just one viable option among many that differ in more than just
incidentals

Can you name an example?

If you're building a PSR-7 application, no matter the architecture, taking
a PSR-7 request and returning a response is ultimately what any PSR-7
application does, regardless of how it does that.

If you're building an HTTP application, no matter the architecture, taking
a request and returning a response is ultimately what any application does,
regardless of how it does it.

Besides mandating the use of PSR-7 models, how do you feel that this
interface implies more architecture than the HTTP message exchange itself?

In my opinion, "takes a request and returns a response" is the broadest
definition you can give and still imply that it's even an HTTP application.

Am I missing something?


On Tue, Jan 24, 2017 at 7:47 PM, Larry Garfield <la...@garfieldtech.com>
wrote:

> This strikes me as drifting too far into the "defining a framework"
> territory.  While I can certainly see the value in the architecture this
> would imply, it's by no means the only architecture.  Many controller
> systems I've seen (including Drupal's, even before Symfony) used one or
> another means of automatically extracting information from the request to
> pass into the controller; loaded domain objects based on the URL, for
> instance.  That creates a shallower and IMO better signature for individual
> controllers, but would be incompatible with the design below.
>
> It's not that the model described here is bad; it's quite powerful.  But
> it's just one viable option among many that differ in more than just
> incidentals, and so I don't think a PSR (which would have the effect of
> pushing everyone toward this one model, which is the point of a PSR) is
> appropriate in this case.
>
> --Larry Garfield
>
>
> On 01/24/2017 10:45 AM, Rasmus Schultz wrote:
>
> Any interest in a simple PSR for Controllers?
>
> What I'm suggesting here is something that is extremely abstract and
> generic - something that builds upon PSR-7.
>
> The interface itself could be as simple as this:
>
> interface ControllerInterface
> {
>     public function dispatch(ServerRequestInterface $request):
> ResponseInterface;
> }
>
> To contrast this with the middleware-interface of PSR-15, "middleware" is
> a component that shares control with other middleware-components, e.g.
> *may* do something to a request, or might just pass - as opposed to a
> "controller", which is a component that *must* process the request and
> create a response, so this would be something to which routing (of any
> kind) has determined that, for the given request, this *is* the component
> responsible for processing.
>
> This would work for front-controllers (such as a middleware-stack based on
> PSR-15) as well as for any other types front-controllers, e.g. anything you
> might use in a catch-all "index.php" as the top layer of request routing.
>
> It would work for any kind of action-controller as well, e.g. using
> abstract base-classes to implement specific dispatch-strategies, and
> assuming any other dependencies would be provided via dependency-injection
> - which would be outside the scope of this PSR, but you can imagine
> abstract base-classes implementing different dispatch-strategies, such as
> dynamically mapping GET or POST params against argument-names of a run()
> method, providing integration with a DI container, etc.
>
> We currently use such a strategy and an identical ControllerInterface at
> work, and it's been a real success. Our default base-class, for example,
> detects a JSON object body being posted, decodes it and maps
> object-properties against arguments - and for form-posts, it checks for
> scalar type-hints of the run-method and performs int, float and bool
> conversions, array and string type-checks, etc.
>
> We enjoy the security of being able to replace our controller-pattern
> completely without breaking compatibility with existing controllers, and
> the freedom of being able to implement highly specialized controllers (such
> as a controller that resizes images) without using a base-class at all.
>
> This pattern and interface makes any controller-implementation compatible
> with any router capable of resolving a request to a ControllerInterface
> instance, or perhaps a class-name for integration with a DI container. (In
> our stack, that means the router is responsible solely for determining a
> class-name - we use a class-per-action pattern, but a router could of
> course also resolve to an action-method name and provide that to a
> controller-implementation via constructor-injection - as with most patterns
> this simple, your imagination seems to be the limit.)
>
> Basically any router that can resolve a path to a string and HTTP-method
> can interop with this - micro-frameworks that go beyond just resolving the
> request to a value (e.g. creates or runs controllers) would likely be able
> to interop with this in other ways.
>
> This is one part of the story.
>
> The other part is about filters - often there is a need to secure a
> controller, accept or reject certain content-types, apply caching, or do
> some other form of filtering before/after actually running the controller.
>
> That sounds a lot like middleware - in fact, a lot of middleware
> components would be immediately useful if a controller could simply apply
> them as filters. So there is no need to invent a new concept here, PSR-15
> would do the job, we only need to define how filters get created.
>
> The following simple interface would do that:
>
> interface FilterInterface
> {
>     /**
>      * @return ServerMiddlewareInterface[]
>      */
>     public function getFilters(): array;
> }
>
> This could be part of the same PSR or separate.
>
> Now a controller can (optionally) implement this and use it to declare
> controller-specific middleware as filters - e.g. return [new
> CacheMiddleware(), new PostFilter()] might apply some caching-headers and a
> POST-method restriction.
>
> Whatever is returned by this method gets run before the controller itself
> is dispatched - in other words, to the last middleware-component
> (PostFilter in this example) the delegate that gets passed does not
> delegate to a middleware-component but to the controller itself.
>
> How precisely the filter-middleware gets dispatched is outside the scope
> of this PSR - it's up to the controller base-class or framework, wherever
> you choose to place this responsibility. An abstract controller base-class
> could support FilterInterface internally, or it could be done in a router,
> middleware or micro-framework.
>
> We haven't attempted the filter pattern in our own stack yet, so I can't
> say for sure if this would work out as dreamy as I think it would - but I
> think we eventually will try it, as there's a very real need and many
> practical use-cases.
>
> As for the controller pattern, it's sort of a no-brainer - it's totally
> trivial, and it just works.
>
> Well, I figured I'd put the idea out there, as it has already had great
> value for us, in terms of decoupling and separating concerns like routing
> and middleware from controllers and dispatch-strategies.
>
> I figure it's worth sharing the idea :-)
>
> Thoughts?
>
> - Rasmus
>
> --
> 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 post to this group, send email to php-fig@googlegroups.com.
> To view this discussion on the web visit
> <https://groups.google.com/d/msgid/php-fig/b6c0ab24-9030-4f0f-aaca-facdfecc9f47%40googlegroups.com?utm_medium=email&utm_source=footer>
> https://groups.google.com/d/msgid/php-fig/b6c0ab24-9030-
> 4f0f-aaca-facdfecc9f47%40googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>
>
> --
> 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/HD5meon7TX0/unsubscribe.
> To unsubscribe from this group and all its topics, send an email to
> php-fig+unsubscr...@googlegroups.com.
> To post to this group, send email to php-fig@googlegroups.com.
> To view this discussion on the web visit https://groups.google.com/d/
> msgid/php-fig/da0de433-f1e4-d534-530c-9d4ae103e42f%40garfieldtech.com
> <https://groups.google.com/d/msgid/php-fig/da0de433-f1e4-d534-530c-9d4ae103e42f%40garfieldtech.com?utm_medium=email&utm_source=footer>
> .
>
> For more options, visit https://groups.google.com/d/optout.
>

-- 
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 post to this group, send email to php-fig@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/php-fig/CADqTB_jFW99UzAEbsh6SZ3NySJ35uj5tQ%2B%3DzeYSkvH%2Bu3asAbg%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to