Skip to content
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

[9.x] Add Route::singleton() method #44872

Open
wants to merge 4 commits into
base: 9.x
Choose a base branch
from
Open

Conversation

jessarcher
Copy link
Member

@jessarcher jessarcher commented Nov 8, 2022

This PR introduces a helper to register routes for "singleton resources" - resources that are either "one of one" or "zero or one".

Example:

Route::singleton('profile', ProfileController::class);
Verb URI Action Route Name
GET /profile show profile.show
GET /profile/edit edit profile.edit
PUT/PATCH /profile update profile.update
DELETE /profile destroy profile.destroy

Many of the options that apply to resource controllers can also be used here, such as only and except:

Route::singleton('profile', ProfileController::class)->except('destroy');

When the resource can be zero or one, a PUT request can be used for both creating and updating the resource because we always know the resource's location. The update name that is traditionally attached to the PUT doesn't make this entirely clear, so we could potentially name it something like upsert instead. Personally, I prefer keeping the existing name rather than introducing a new action name.

Singleton resources can also be nested within a standard resource for cases where a resource is singular in the scope of the parent resource:

Route::singleton('videos.thumbnail', VideoThumbnailController::class);
Verb URI Action Route Name
GET /videos/{video}/thumbnail show videos.thumbnail.show
GET /videos/{video}/thumbnail/edit edit videos.thumbnail.edit
PUT/PATCH /videos/{video}/thumbnail update videos.thumbnail.update
DELETE /videos/{video}/thumbnail destroy videos.thumbnail.destroy

Route model binding would work for the Video model in the above example, but there is no model binding for singleton resources because the URL does not provide enough information to resolve it. In many cases, there may not even be a dedicated model for the singleton resource. In the above example, the thumbnail could be a separate model, but it could equally just be an attribute on the Video model that warrants its own routes.

For parity with the resource methods, there is also an apiSingleton method that excludes the edit action, and there are singletons and apiSingletons methods for bulk registration.

* @param array $options
* @return void
*/
public function __construct(ResourceRegistrar $registrar, $name, $controller, array $options)
Copy link
Contributor

@dammy001 dammy001 Nov 8, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use PHP 8 constructor property here

Copy link
Member Author

@jessarcher jessarcher Nov 9, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This class matches the PendingResourceRegistration class that was created prior to PHP 8.

@lukebouch
Copy link

lukebouch commented Nov 8, 2022

This looks super useful, @jessarcher!

@bjhijmans
Copy link

bjhijmans commented Nov 8, 2022

In your examples you have routes to destroy a singleton. Shouldn't you also be able to create and store one if it doesn't exist?

@jessarcher
Copy link
Member Author

jessarcher commented Nov 8, 2022

In your examples you have routes to destroy a singleton. Shouldn't you also be able to create and store one if it doesn't exist?

The intention would be that you'd always make a PUT request, regardless of whether the resource exists or not.

@jessarcher jessarcher marked this pull request as ready for review Nov 9, 2022
@lukebouch
Copy link

lukebouch commented Nov 9, 2022

That makes sense, @jessarcher.

@bjarn
Copy link

bjarn commented Nov 9, 2022

What about Route::crud(...). Might be a better descriptor for this case as there can be many videos or many profiles, but you basically want to generate these crud routes.

Anyway, nice addition!

@jasonmccreary
Copy link
Contributor

jasonmccreary commented Nov 9, 2022

Nice. I've definitely created these types of resources by hand before.

My only change would be the name. If this is always a resource, which it seems to be, I'd suggest singletonResource (or soleResource) to align with apiResource. I appreciate it's a bit more to type, but singleton alone feels like the container.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants