Comments (6)
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.
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.
These are hectic days for me, but as soon as I become free, I'll definitely consider your idea!
from harmony.
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.
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.
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)
- Add better support for dispatching middleware conditionally HOT 4
- Improve the Read Me HOT 3
- new install error HOT 2
- Lazy Loading? HOT 5
- LaminasEmitterMiddleware not available in the middleware HOT 1
- Any plan to release a new version? (for PHP 8 support) HOT 1
- Return a Response object for all the middlewares. HOT 6
- What's the point of the "terminated" property? HOT 1
- Use StyleCI for CS checks AND fix HOT 1
- A few travis config observations HOT 11
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from harmony.