Route model binding, Provider, Middleware, constructor or function specific - laravel

In most projects, you often have a route where you have multiple params
/posts/1/comments/1
And you want to make sure that comment 1 is part of posts 1.
You can do these multiple ways.
Abort_if() or Abort_unless()
Like this
abort_if($post->id != $comment->post_id, 403);
or
abort_unless($post->id == $comment->post_id, 403);
The con is that this needs to be at every controller function that interacts with both comment and post. A lot of repeating code. Not really that DRY
Middleware
You could make a middleware that does this check, and place it on the desired route.
The con with this one, you'll need to place this at every route you need this, the same thing like the abort option.
Route model binding
This looks like the best option, a global way of querying from the posts model.
$posts->comments()->where($comment->id);
The con here, if you bind 'comment' to be always searched in the relation of posts then you will never be able to do
/comments/1
What are your thoughts? Can't really seem to find a best practice nor a definitive answer.

Related

Laravel 5: find the page number of an entry

I'm working on a custom forum and when a post is added to a thread I have to notify the subscribed users. In the message I have to place the link for the user to go straight to the post. Something like this:
/forum/discussion/1/ateliers-et-expositions?page=2#forum-message-3
To be able to do that I need to know the page number of the entry. Does this feature exist on Laravel already? I couldn't find it in their docs and I know about features that exist but are not in their docs, so maybe it's there already and I'm just not aware of it.
I would like to avoid making a select in the database a loop through it to find the page number, if possible.
You most likely look for get() method of Request class. Assuming you want to get this in your controller method, say foo(), you should have:
use Illuminate\Http\Request;
public function foo(Request $request)
{
$page = $request->get('page');
...

Laravel: form method != save method?

I am new to Laravel coming from CakePHP where the form and save method for a form is one and the same function name. I saw in many Laravel tutorials that the from method (that displays the form) is different than the method to save form (that actually saves data). Why using 2 different method names?
For example what's wrong with:
pub function xyz(Request $request)
{
if($results->isMethod('post')){
... then save and return redirect
}
... the code for showing the form in case there is no POST.
then having 2 routes one for GET and one for POST on the same url?
It is because people like to filter out things at route level not in controller, Also it helps developer to apply middleware grouping for each route separately. so that they can apply roles and permission etc. easily at route level.
It will looks horrible if mix all things in controller.
Think about middleware and groups in your code.
It is because you don't wanna mix a lot of logic in the same method . The case you have simple is the simple scenario . But there will be case where you wanna pass initial data in the create form . You have to write logic for that also in the same method and while you store the data you need to do the validation and calculate other business logic . If you combine all those things in one method it will mix all the things in one method and code difficult to read

Laravel return from controller and continue routing

I haven't found an answer whether it is possible to return from a Laravel controller back to routers and continue searching for another route. Or maybe, another approach would be useful to solve this:
The goal is to have blog articles with url following the domain name like this:
domain.com/url-of-blog-article
so, my route looks like this:
Route::get ('{articleUrl}', 'WEB\BlogController#showArticle');
However, if the article with the requested url doesn't exists, I would like to return back to the router and continue with searching another page. One solution might be to put this route to the end of the router. But, is there a way to return from the controller without a view?
I don't believe that's possible. Moreover, even if it were, I wouldn't recommend it -- your application would waste time searching the database for an article that doesn't exist, and it would go against the router's convention of matching a single route for a given URL.

Adding attribute to a user when register in Laravel 5.1

When a user Register, I want to add location data for the user.
I get those with GeoIP.
So, each time a user is created, I would like somewhere to add Country, City, etc.
I was thinking about setting Hidden fields in view, but I think it a hugly way to do it, and I'm sure there is a better way to do...
Any Idea???
Any time I create a record that needs extra data, involves inserting additional records into additional tables, etc, I create a service class. Something like "UserCreator" then I pass it the input, do any additional operations, wrap multiple database calls in a transaction and so on.
That said there are so many ways to do what you want. You could Input::merge(...) then save, you could separate the process of creating a user from your controller / route function, etc.
If you are just getting started with Laravel and/or your project is rather simple, then you probably want to look at Input::merge
I solved it using Request Contructor as said here in laracast
In the Form Request's constructor I inject \Illuminate\Http\Request. I can then add my value to the request instance as such:
public function __construct(\Illuminate\Http\Request $request)
{
$request->request->add(['date_of_birth' => implode('-', $request->only('year', 'month', 'day'))]);
}

MVC3 Routing - Routes that builds on each other

I have an AREA setup in my project. I need to make the routes for the area progressive, meaning that the route will build on each other.
I'm looking at this as something like a link list. Each node in the list will have a reference to a parent. As move from left to right in the list it builds, and from right to left it removes.
In the area, I have companies and that have contacts, and child companies.
For example, I have companies that would have the following:
/Companies/list
/Company/{Id}
/Company/{id}/add
/Company/{id}/edit
/Company/{id}/delete
For the contact section I need to create the following routes:
/Company/{id}/contacts/list
/Company/{id}/contact/{id}/add
/Company/{id}/contact/{id}/edit
/Company/{id}/contact/{id}/delete
How do I make sure that /Company/{id} is always in the Contact and Child Company sections of the route?
I hope that I have made my question clear.
Subjective Generalities (take with a pinch of salt):
First off, you are using Company (singular) for companies, but then you are using contacts (plural) for the contacts. There is nothing wrong with this, from a structural point of view, but your users will thank you if you are consistent with your pluralizations. I would use the plural in both cases, but that is just my preference... it looks more like English.
You also use lower case for contacts, but upper case for Company. Doesn't look professional.
The next thing that is confusing is that you are using two {id} parameters, one for companies, one for contacts. I presume these are the ids for Company and Contacts respectively. But I am confused, but being human, I am able to deduce context unlike a computer. So you would be better of specifying the parameters in your routes. Ie:
/Companies/{CompanyId}/Contacts/{ContactId}/[action]
Answering your Question with an Example:
I get the feel you don't understand routes properly. If you did, your question would be more specific.
Your route parameters can come from a number of sources, depending on how the route is requested.
You could hard code it into a link. Or, more usefully, your route registration would be designed to catch requests that map to your Action signatures.
For example, I have an eLearning app with tutors, pupils, courses and steps (ie, the steps are like sections of a course, the pupil advances through the course step by step)
The route registration looks something like:
Route or Area Registration:
context.MapRoute(
"StepDisplay",
"Course/{CourseId}/Step/{StepOrder}/Pupil/{PupilName}/{TutorName}",
new { controller = "Course", action = "Display", TutorName = UrlParameter.Optional },
new[] { "ES.eLearningFE.Areas.Courses.Controllers" }
);
This route will catch a request from the following ActionLink:
ActionLink in View:
#Html.ActionLink(#StepTitle, MVC.Courses.Course.Actions.Display(Model.CourseId, step.StepOrder, Model.Pupil.UserName, tutorName))
Now, I just need to show you the Display action's signature:
CoursesController:
public virtual ActionResult Display(int CourseId, int StepOrder, string PupilName, string TutorName)
There are a few things to note here:
That I am able to call this specific route by giving the user a link to click on.
I construct this link using the Html.ActionLink helper
I have used David Ebbo's t4mvc nuget package so that I can specify the action I am calling and its parameters. By which I mean specifying the ActionResult parameter of the Html.ActionLink helper using:
MVC.Courses.Course.Actions.Display(Model.CourseId, step.StepOrder, Model.Pupil.UserName, tutorName)
If you think about it, what routes do is translate the url of a request into an action, so the parameters of my route are either the controller name, the action name or else they are the names of parameters in the action signature.
You can see now why naming two distinct route parameters with the same
name is such a bad idea (largely because it won't work).
So, look at your action signatures, and design your routes and your action links so that the everything marries up together.
MVC doesn't work by magic!! (Although the way it uses name conventions might lead you to believe it)

Resources