-
Notifications
You must be signed in to change notification settings - Fork 11.6k
Adds support for Attribute-based Routing (MVP) #56424
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Thank you for not making it a default. If this gets merged, symfony lovers will clap their hands like a circus seal. |
64552fd
to
527fdea
Compare
I have a project, where we have more than one directory of web routes and many API routes directories, some of them are located outside of App namespace. I think this should be more flexible. |
You can easily specify a list of folders to scan, ->withAttributeRouting(
web: [
base_path('src/Invoicing/UI/Web'),
base_path('src/Customers/UI/Web'),
],
api: [
base_path('src/Invoicing/UI/Api'),
base_path('src/Customers/UI/Api'),
]
) Of course, this is just an MVP version; if its addition is approved, other features will be added as well. |
Test are failling |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could this be an attribute as well, instead of an interface? It seems that things are moving away from using empty interfaces to mark functionality and towards using attributes instead.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hello,
Thanks for the review.
If I understood correctly, you’re referring to the AttributeRouteController
interface. In this pull request, I initially made the system explicit by requiring that interface.
If this pull request is accepted, we could also add an implicit mode so that all controllers are scanned without needing to implement the AttributeRouteController
interface.
I’d also be happy to hear if you think there’s a better approach that could be implemented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AmirHkrg I'm suggesting using an attribute instead of an interface since the interface is empty and appears to be used as just a marker.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we want to avoid using an interface for marking altogether, the best approach would be the implicit one — defining routes only with attributes, without any additional requirements.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume, you talk past each other. Afaik, Will meant this:
https://www.php.net/manual/en/language.attributes.overview.php
<?php
namespace App\Http\Controllers;
use Illuminate\Routing\Attributes\{Get, Group, Post};
use Illuminate\Routing\Attributes\AttributeRouteController;
#[Group(prefix: 'users', name: 'users.', middleware: 'auth')]
#[AttributeRouteController]
class UserController extends Controller
{
#[Get('/', name: 'index')]
public function index()
{
// Route: GET /users
// Name: users.index
}
#[Post('/', name: 'store')]
public function store()
{
// Route: POST /users
// Name: users.store
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @shaedrich
Yes, I understand their point, but I followed the current structure and conventions of Laravel. As you can see, Laravel uses interfaces for marking, such as the ShouldQueue
and ShouldBeUnique
interfaces in queues.
It is possible to use attributes for marking as well, but it would work a bit differently compared to other features.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey Amir, no offense, but this is short-sighted. Of course, Laravel has that structure. This is for historical reasons. When Laravel was created, there were no attributes. And if we would rectify everything with "we've always done it that way" and limit ourselves to only what had already been available at that time, there would be no progress.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Certainly, if I look at it from your perspective, it’s completely valid, and it could be really good to be a pioneer in using new approaches.
I’ll replace the interface with attributes, though having both together might not be a bad idea either.
Of course, it’s also important that the Laravel team agrees with us, since this pull request itself might have a low chance of being merged.
Thanks for your pull request to Laravel! Unfortunately, I'm going to delay merging this code for now. To preserve our ability to adequately maintain the framework, we need to be very careful regarding the amount of code we include. If applicable, please consider releasing your code as a package so that the community can still take advantage of your contributions! |
There are great attribute routing packages in the community 👍 |
This pull request introduces the foundational support for attribute-based routing in Laravel. It provides a clean, modern, and developer-friendly way to declare routes directly on controller methods.
Discussions
Motivation
As PHP continues to evolve, attributes have become a powerful tool for declarative programming. Many modern frameworks have adopted them for routing, which helps co-locate route definitions with their corresponding logic, improving clarity and developer ergonomics. This PR aims to bring this same modern convenience to Laravel, embracing modern PHP capabilities more deeply.
Crucially, this system is designed to work in conjunction with the traditional file-based routing system, not as a replacement. Developers can use both methods side-by-side in the same application, giving them more flexibility in how they organize their projects.
Proposed Solution
The feature is opt-in and enabled via a new fluent method,
withAttributeRouting()
, inbootstrap/app.php
.Developers can easily specify which directories should be scanned for
web
andapi
route groups. If called with no arguments, it uses a sensible default.Controllers are marked for discovery by implementing the
AttributeRouteController
interface. Routes and groups are then defined with simple attributes:Performance Considerations
The performance impact of this feature has been carefully considered. In local development, a negligible overhead of a few milliseconds is introduced by the file scanning process. However, in production, once routes are cached using
php artisan route:cache
, there is zero performance impact. The only change is a simpler and more enjoyable development workflow.This is an MVP
This initial pull request implements the Minimum Viable Product (MVP) for this feature. The goal is to first agree on the fundamental architecture and API.
I have already locally developed and tested more advanced features that can be added in subsequent PRs upon approval of this core concept. These future possibilities include:
#[Resource]
and#[ApiResource]
attributes for full RESTful controller support.#[Group]
features likeonly
andexcept
for targeting specific methods.scopeBindings
support for both resources and groups.implicit
discovery mode to reduce boilerplate.route:list
andmake:controller
).Currently, there are third-party packages available for this purpose, but it’s possible to offer such a feature — which already exists in most modern frameworks — directly within Laravel itself. This would allow for greater compatibility, a more controlled structure, and higher flexibility. For example, editing route commands and similar functionalities that cannot be modified in third-party packages.
It could also be developed in a much more advanced way with newer and more complete ideas, aligned with Laravel’s philosophy.
Of course, I understand that adding more logic and code will make development and maintenance more challenging. However, I am capable of carrying out the full development, and Laravel’s large and active community will also help along the way.
Next Steps & Collaboration
I am fully committed to seeing this feature through to completion. If this initial proposal is accepted by the team and the community, I am ready to collaborate on any necessary changes and submit the subsequent PRs to build out the full feature set.