Demers94's avatar

Controller methods convention for two routes that display the same information

Here's the scenario I'm working with : a job website where users can create job posting and other users can view a list of said job postings.

When the users hit the / route, it calls the index() method of an OffersController where all the current job postings are fetched and a view is rendered. Simple enough!

Now, I want a page where the users can view the job postings that they have created. At the moment, I'm mapping the /my-offers route to a ownOffers() method on the same OffersController.

Both page display the same information, a list of offers, but they do it differently enough (one is just the job postings that belong to a user, the other is all job postings) that it needs two routes, of course. They also render a different view, since I don't want the same page layout for both.

What naming convention would you use in this case? If you follow a "resourceful controllers" approach, then they're both index() for the OffersController.

Would it make more sense to make an other controller, OwnOffersController and use the index() method on that instead? Seems a bit overkill, but at the same time I'd like to avoid controllers with a dozen of non-RESTful methods in them.

Any feedback and suggestions are appreciated!

0 likes
7 replies
clay's avatar

I like dhh's advice:

...whenever I have the inclination that I want to add a method on a controller that’s not part of the default five or whatever REST actions that we have by default, make a new controller!

and Taylor Otwell's

... a lot of people's architectural problems would be solved by having more controllers.

Maybe a UserOffersController, so you could show offers by whichever user you want.

Personally, I like the ADR approach. Create action specific controllers and just have an __invoke method for each. You end up with a lot of controllers, but you have a clear single purpose for each and you end up with fewer dependencies per controller.

2 likes
goatshark's avatar

@DEMERS94 - I've been doing whatever I can to use only the "normal" rest methods in my controllers and to, instead of making up new methods, create more controllers. Like @clay mentioned, UserOffersController or something of the like is where I'd be going with it. Then you can keep with only using index/show/create/store/edit/update/destroy.

Btw - after a few months of striving for this, I really like the way things are turning out in my projects. Things seem way less mentally taxing this way - not having to constantly reverse engineer controllers I've built to re-figure out how to use them.

@clay - This __invoke strategy that you invented... I would love to see an example of it if you wouldn't mind posting one. I have never seen that or thought about doing it. It sounds interesting. Also, if you're thinking about claiming that you did not invent __invoke, it's too late. I already made a note that you invented it. Way to go!

Cronix's avatar

I'd do a new controller as mentioned, but probably name it OwnerOffersController since it's a bit more clear semantically.

Demers94's avatar

Thank you @clay, @goatshark and @Cronix for the feedback!

I like UsersOffersController, makes more sense than OwnOffersControllers. OwnerOffersController is good too.

@clay, what is that _invoke() approach?

clay's avatar

@goatshark If you google 'action domain responder' you'll find some examples. There's many blog posts and several videos about it from various conferences.

Also, @martinbean blogged about implementing the full ADR pattern in laravel.

I don't implement the full pattern, but i do incorporate several of the key concepts in my own apps.

martinbean's avatar

@clay Thanks for the mention :)

@Demers94 It definitely makes sense to have two controllers, each with an index() method. If a user is able to view their own job “offers” in some sort of account area, then you could maybe use name-spacing:

Route::get('/', 'JobOfferController@index');

Route::group(['middleware' => 'auth'], function () {
    Route::get('account/offers', 'Account\JobOfferController@index');
});
1 like

Please or to participate in this conversation.