Giter Club home page Giter Club logo

Comments (6)

kocsismate avatar kocsismate commented on May 26, 2024

Hey!

Ah yes, thanks for asking this interesting question! I have thought about whether my interface design is better or not than the current "industry standards" quite a lot, but of course I couldn't find a definitive answer.

Initially, my intention with this design was to give maximum power to middlewares, so that they can use the application's IoC Container and any other capabilities of the framework.

An advantage of the design now is that the course of routing and dispatching of a respecting controller can be separated, because the router first populates the dispatcher field in Harmony which can be fired separately afterwards. I don't know if it really worth the price, but back then some months ago, I really felt that these two things shouldn't be done in one step. And this is my intuition now too.

Another reason of the design was to be able to manipulate middlewares on the fly (adding and removing), and I even wanted that one could skip to a specific middleware from the current middleware (so you could call $harmony->skipTo("authentication") instead of $harmony->next()). P.S. That's the reason why all middlewares must have an ID. Unfortunately, I haven't implemented the skipTo() method, as I became unsure if it is really useful and not even harmful.

So I certainly want to avoid framework interoperability issues (that was one of the motivations of Harmony), but as long as there isn't a de facto standard interface for middlewares, true interoperability would be very difficult to reach, because besides the middleware interface design you mentioned there are more popular ones too. My favourite of them is the following (and I remember Matthew Weier O'Phinney advocating it too):

public function __invoke(ServerRequestInterface $request, ResponseInterface $response, callable $next);

I read about it from here https://mwop.net/blog/2015-01-26-psr-7-by-example.html

So I feel real middleware interoperability can only be possible when PHP-FIG creates a PSR for it. But I would be curious about your opinion and your usecases too! Maybe some kind of compromise can be found :)

from harmony.

mtymek avatar mtymek commented on May 26, 2024

Let me show it on concrete example. I wrote a simple URL shortener using PSR-7 and with middleware approach in mind. I didn't plan to use it with any specific framework, I want everybody to be able to plug it into their app. One of its features is redirecting to long url (http://bit.ly/xxxx => HTTP 301 => http://some-long.url/with-long-path). I wrote a middleware for it:

class RedirectMiddleware
{
    private $shortUrlService;

    public function __construct(ShortUrlService $shortUrlService)
    {
        $this->shortUrlService = $shortUrlService;
    }

    public function __invoke(ServerRequestInterface $request, ResponseInterface $response)
    {
        $url = $this->shortUrlService->expand($request->getUri()->getPath());
        if (!$url) {
            return $response->withStatus(404);
        }
        $response = $response->withStatus(301)
            ->withHeader('Location', $url->getLongUrl());
        return $response;
    }
}

Currently I have it plugged into zend-stratigility (https://github.com/ezimuel/zend-stratigility-skeleton). It also uses container from container-interop, so dependencies can be injected via constructor - no service locator pattern, good OOP.

Two problems that your implementation addresses could be solved in a different way:

  • maybe populating dispatcher could be done by setting an attribute of incoming request

  • you could create interface that would inform Harmony that given middleware provides an ID:

    interface MiddlewareIdProvider {
    public function getId();
    }
    
    class HarmonyMiddleware implements MiddlewareIdProvider { /* ... */ }

    ... and if it does, Harmony would allow things like skipTo.

It's difficult to predict what kind of middlewares we will see, but with this approach, Harmony would be able to support many 3rd party libraries. If someone wants to write middleware using specific features of Harmony, he can implement an interface (or interfaces).

Obviously, it is not the only approach that will work. You can also create a generic bridge middleware, and automatically wrap callables not implementing Harmony's MiddlewareInterface:

class Harmony {
    public functio addMiddleware($middleware) {
    if (is_callable($middleware)) {
        $middleware = new HarmonyMiddlewareWrapper($middleware);
    }
    // ...
    }
}

On other topic, SkipTo itself indeed could be risky, but it may by also powerful tool. I would think of actual use case first to judge it should be implemented.

from harmony.

kocsismate avatar kocsismate commented on May 26, 2024

These are hectic days for me, but as soon as I become free, I'll definitely consider your idea!

from harmony.

kocsismate avatar kocsismate commented on May 26, 2024

I have great news in connection with this issue! Yesterday, I couldn't resist to think about this problem and I think I have found a solution which "eases all"!

After some research, I became super enthusiastic about Zend Stratigility's interface, so I decided to implement it in a simpler and even more lightweight fashion (I didn't really like its error handling part for the first sight).

So now a middleware in Harmony is a callable with the following signature:
function(ServerRequestInterface $request, ResponseInterface $response, callable $next).
The usage is almost the same as in Zend Stratigility: (except of that errors cannot be raised and there is no such concept as FinalHandler yet). I know that "almost the same" is not "the same" at all but I hope my implementation will be enough for a basic middleware to be able to be used in more frameworks. I think supporting FinalHandler in Harmony would also be important in the near future.

And the trick I used to provide more capabilities for middlewares written exclusively for Harmony was that the middleware signature can be changed to
function(ServerRequestInterface $request, ResponseInterface $response, Harmony $next) and thus, one can use Harmony::skipTo() (I implemented it just to play with it) and any other capabilities of the framework. Changing signature is possible because Harmony itself implements __invoke()!

Another thing is that I decoupled Harmony from ContainerInterface, so if a middleware wants to use a DIC (like the DispatcherMiddleware), it must be injected into it. And I liked your idea about using an attribute of the request to store the dispatchable controller (although it seems to be a bit nasty :P).

So thank you very much for your proposal I appreciate it very much. I like Harmony's new design! And I hope that you like it too. Anyway, I am looking forward to hearing about your opinion and criticism!

from harmony.

kocsismate avatar kocsismate commented on May 26, 2024

Update: I implemented the final middleware functionality (but only one can be attached now) and removed skipTo as i realized that I only wanted to use it to skip to the last middleware.

from harmony.

mtymek avatar mtymek commented on May 26, 2024

Thanks for the updates. Looks like your changes are in line with what I've been thinking. Not much to add now - so far your code is would work fine with my middleware.

from harmony.

Related Issues (11)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.