Playing
01. Dynamic breadcrumbs in Laravel

Episodes

0%
Your progress
  • Total: 21m
  • Played: 0m
  • Remaining: 21m
Join or sign in to track your progress

Transcript

00:00
Breadcrumbs are one of the things that can be really tricky to implement but also get really messy when you do implement them. What we're going to do in this little snippet is just take a look at reading the segments
00:12
of the URL and generating our breadcrumbs. Now, we're not just going to stop there because, of course, we are more than likely going to have models injected into our route. So, for example, here I have a category and then I have an article here as well.
00:28
And what we're actually doing here is we're detecting via the route that these are actually models and we're going ahead and plucking out the title from these rather than converting over the segment to a title case. So just as an example, the reason that this is useful, if, for example, we had how to
00:45
make breadcrumbs two or, in fact, the year in here, then, of course, if we just come over to the database and change around the slug in here, we're not going to see 2018 inside of the breadcrumbs. We're actually just going to see the title of the article.
01:02
So I've set this up as a partial so we can click back here onto all of these example pages and, as you can see, they are showing the parent categories and we can successfully link through. Now, if you want a way to manually build up breadcrumbs, I'd highly recommend this package
01:16
just here. Go ahead and read through this and this might suit your needs a little bit better. But if you have a URL like this and you want to go ahead and build up breadcrumbs, then keep on watching and we'll see how to do this.
01:28
Okay. So I've just gotten rid of the breadcrumbs partial. Let's first of all just take a look around how this app is set up. Really basic routing here.
01:37
We have a root group with an articles prefix. This root here on this controller will show perhaps a list of all the latest articles. Then we can dive down deeper into a category. So this will be articles slash category and that will, of course, list out all of the
01:51
categories. And then we have the ability to view a specific category, which will probably show us what it will, all the articles inside of that category. And then within that category, we can pick out a particular article.
02:03
Now the reason that this is important is this is, like I said a couple of minutes ago, this is based on the URL structure. So if your URL structure is very simple, then of course breadcrumbs are probably not for you anyway.
02:16
Okay. So all of these methods here inside of these controllers are returning a view. They're all incredibly simple. The only more complicated one is this where we're outputting the title of the article.
02:29
So we're going to take this in a couple of steps. The first thing I'm going to do is just come over to the partial that I've got rid of. This is currently empty and it's included on all of the pages where I want to see these. Let's go ahead and create out a nav element inside of here.
02:42
Let's create an unordered list in here and make this bootstrap friendly. So let's go ahead and give this a class of breadcrumb. Then inside of here, we have a list item and all of these list items have a class of breadcrumb item.
02:56
So for example, the anchor in here to go home will probably always be visible. So we can at least kick things off with that. Now of course here what we need to do is iterate through all of the segments in the URL and then go ahead and display them.
03:10
So that might seem pretty straightforward first off. So let's do a for each loop and let's go ahead and assign the segments while we're doing this so we can access them without re-requesting this from the segments method. And let's go ahead and pull in the index of these so we know the position and the segment
03:29
as well. So let's go ahead and end that for each loop just here. And let's just go ahead and output the segment just very briefly just so we can see what we get.
03:38
So of course we get articles, categories, tutorials and then the slug of the actual article itself. So we're already making fairly good progress. Now of course let's put this into an anchor just inside of here.
03:48
This isn't really appropriate at the moment but you can see that that gives us the following. And of course this needs a class of breadcrumb item just to start that out. Okay. So the first thing that we could do is convert the case over for this.
04:01
So we could use the title case helper in Laravel. That's of course going to give us a title case. But of course for this in particular we have a little bit of a problem with the hyphens in here since it's a slug.
04:14
And also the problem I mentioned earlier, whatever you have inside of your slug is going to be visible just here. So what we could do if we just come over to our views, the first possibility is to come over to our show.blade.php and pass in a model.
04:29
I've already done this. I didn't change it from a moment ago. But we can pass in the model that we want to use for the breadcrumbs. Now this isn't very efficient.
04:37
We're going to look at a way to break this up into a class a little bit later on. But at least for now what we can do is take the article in and inside of the breadcrumbs check if it's a model and then output the property we want if that's the case. So we can do this all in line.
04:51
Let's just pull this down for just a moment and let's just start this off fresh just above here. So I'm going to say, well, if the model that I am wanting to output is set and the index that we're currently at equals the count of the segments minus one, then we know that
05:11
that's the model. So let's just go ahead and output in here the model title. And then otherwise we can go ahead and output the title case of the segment. And I'll go over why this is working in just a second if it's not clear.
05:26
So if I give that a refresh, sure enough we get what we would expect. Now the reason this is working and it's a little bit hacky and not really that great. Basically what we're saying on this page is this is the final page that we're at and this is the model that we're displaying.
05:40
So we are kind of relying on the fact that this is the last thing. So therefore we're just checking if this is the last thing and we have a model set, then we output the model title. So it's not very efficient.
05:52
When we start to break this up into a class and use a request macro, this is going to be a lot better. So what about the URL? Now this is a little bit trickier.
06:01
So let's go and see what we can do with this. So what we need to do is say at the point of tutorials, we just can't click back on it just yet. So let's get rid of that.
06:11
We want to say, well, take the first thing here, which is the homepage. So we'll assume that that is just the domain you're working on. Then take articles, categories and tutorials and grab all of the items in here and then kind of implode them together with a slash.
06:27
So we end up literally with this just here. So because we know the index, what we can do is slice the segments array that we have just here from zero to the index that we're currently at and then we can implode that back again.
06:42
So just to demonstrate this, let's see if we can just output this up here. Let's go ahead and say array slice. Go ahead and grab our segments inside of here and we're going to go ahead and slice them from the start because of course home isn't part of our segments.
06:59
And then we're going to go to index plus one. Now let's just get rid of this here and I don't think we're going to be able to see this in here of course. So let's just go and do a die dump on this just so we at least see something inside of
07:12
here. So at the moment, we just get articles. That is because that is the first breadcrumb item. If we instead change this over to file dump, sure enough, what we get is articles, then
07:23
articles, categories and articles, categories, tutorials and so on and so forth for however many pages we have. So we're slicing these at each of these points and then we can rebuild this up into a URL because of course to go back, it would just be the same URL structure.
07:39
So to do this, we are going to go ahead and implode this so at least we can see it on the page and we'll just implode then broken up pieces by a slash because of course it's a URL. And sure enough, what we get is the articles page when we click on here, articles, categories
07:53
when we click on here and so on and so forth all the way up to the last item just here. Now of course we need this to be an actual URL so let's wrap this in the URL helper which will take this from the base part of our app and now we have a built-up URL that we can go ahead and place into the href inside of here.
08:11
So now I can go ahead and click through here and that is pretty much a simple way to get this working. Now the problem I mentioned earlier, let's say that we just change the slug over for tutorials.
08:21
So let's come over to categories and let's just say code course tutorials. We'd probably just want tutorials to be displayed there but of course it's not going to work if we just of course switch the slug over in the URL. We get code course hyphen tutorials.
08:37
So what we then have to do is start saying, well, if the model is set and the index equals that particular index but then again this model only is the article model so we're going to end up in a huge mess. So what we're actually going to do is scrap all of this and we're going to go ahead and
08:53
rebuild this out using a request macro and we're going to build up our own class for this and this is a much nicer way to handle this and just my implementation of it. So let's go ahead and just get rid of this for each loop altogether actually because we already know what kind of markup we want and we're kind of back to square one here.
09:11
So the first thing that we're going to do is come over to app and I'm going to create a breadcrumbs folder. Of course you can put this anywhere you want, perhaps in a helper's directory and let's go ahead and create out a breadcrumbs.php class in here to kick things off.
09:26
So let's pull the namespace in for this and let's head over to our provider section over in app service provider and let's go ahead and create a request macro so we can use this directly from the request object. I'm going to go ahead and call this breadcrumbs with a lowercase b just there and I'm going
09:44
to go ahead and create a closure in here and when we call the breadcrumbs method on the request anywhere we are in our application, this will go ahead and return a new breadcrumbs class and we're going to pass this in as a dependency which is of course because we're creating a macro here, the request itself.
10:03
So let's go and pull the namespace in for this at the top and make sure that we pull the request namespace in as well and let's just come over to our app and see what might be the problem here so the name is already in use and of course that was just from earlier. Okay so now what we can do is just test this out, let's come over to our article controller
10:22
and inside of here let's die dump on request breadcrumbs and see what we get and sure enough we get that breadcrumbs class. So over in the breadcrumbs class we know that we want to accept the request in as a dependency here so let's go ahead and accept this type hinted request in and we'll just go ahead
10:43
and assign this just up here like so and of course pull that in as a property at the top as well. So we now have our request in there, so once we pull the namespace in for that, perfect so we've got our request in there now and we can start to pretty much do everything
11:00
that we've just done inside of Blade but inside of this class along with the other things that we want to kind of get fixed up. So let's go and create a method in here called segments, this is going to return to us all of the segments so what I like to do when I'm building out things like this is I like
11:17
to write the code that I'd like to see. So for example I'm going to say request breadcrumbs and I probably want to iterate over each of the segments like this as a segment and that should just about do it for now. So let's go and in here output the segment and how would I want to access this, well
11:38
I'd probably want to access this by name so I might have a name method on each of the segments and the reason that this is important is inside of segments we're going to create a new segment class which will be responsible for holding all of the information about that particular segment, we're not going to overload this class with too much information.
11:56
So let's go and just really quickly create a segment.php file inside of here and let's go ahead and create this segment class out in here like so and over in breadcrumbs what we want to do is collect up all of the segments so we can use this request segments like we did inside of our view then we're going to go ahead and map through these and essentially
12:23
convert these over to a segment object. So let's return a new segment for each of the segments, let's pass the request in because we're going to need some information for that and let's pass the name of the segment, remember that this is just a string and we'll get that inside of here.
12:40
So let's pull the namespace in for the segment just there and that should be just about it. The only other thing that we need to do here is call to array on our collection so we actually get an array that we can iterate over. So if we come back over to our article controller where we're kind of previewing this, let's
12:56
go ahead and call the segments method and give that a refresh and sure enough we get an array here with a segment object for each of the segments and then from each of them segments we can implement the methods on there that we need to output the name and all that kind of stuff.
13:12
So let's just close everything off just to keep things nice and tidy and we're pretty much done in here. If we come over to segment now, we can start to accept in what we need in the constructor. This is pretty straightforward.
13:24
We just want to accept in the request and the segment as well which again remember is just a string. So let's go ahead and just pop these up here, keep things nice and tidy and we should be good to go.
13:40
Okay, so let's just try the name method that we created just a second ago. Basically all this is going to do is return the segment itself. So if we just give this a refresh now, it looks like we just need to pull that in of course and there we go.
13:54
So we now have kind of back to where we were before we're outputting the name but of course what we want to do is go ahead and give this a title case so it displays a little bit better. Okay so if we come over to our breadcrumbs partial, let's go and create a list item in here, create an anchor and pop that inside of there and we'll go ahead and give this
14:14
a class of breadcrumb item just to make that look a little bit nicer. All right, so like I said we're back to square one. What we can now start to do is look at the URL and then of course the model stuff. So let's create a method for the URL and let's just redo this.
14:31
We won't bother copying and pasting anything over. Of course this is going to be a URL so we can wrap this and we're going to go ahead and use array slice using this request segments and remember we cut this from position zero to a position.
14:48
Now we don't actually have the position of this just yet so let's call a position method and let's add one on to that and then of course let's go ahead and implode this. So this is exactly what we were doing before. The only difference is we don't have the position of this particular segment right now but we
15:05
do have access to the request so we can go ahead and search for that inside of the request. Now I'm going to go ahead and make this a public method just so if we needed to access it for any reason we could do. Just inside of here, let's just die dump on this position just so we can see this and
15:24
let's go over to breadcrumbs and output the URL just so we can see that in there and let's go ahead and return just zero for now. So let's give that a refresh and sure enough we see zero. So inside of the position then we want to go ahead and do a search so we can use array
15:40
search to look inside of the segments for this particular segment. That will give us the index or the key of that particular segment and then we know the position because we have the request on that particular segment. So let's go ahead and say this request segments again and sure enough we should have the correct
15:59
position. Now that does not exist, segment, so let's go ahead and fix that up. So we still get zero because of course we've done a die dump here. Let's go ahead and do a var dump instead and we should see if we just call the correct
16:12
method here. So let's say segments, keep spelling that in correctly, we should see 0, 1, 2, 3 and so on and so forth. So we know the position now.
16:21
So now that we've got the position, the URL should be successfully generated for each of these because this is exactly what we were doing inside of our blade template where we were iterating through it and grabbing the index inside of that for each loop. So that is now working as we would expect.
16:37
So let's just switch this up. Of course we don't want the URL to be in there. We want the URL to be in there and of course the name can just go out there as well. So this is now working again as we would expect.
16:49
The last thing that we have to do is try and detect if each of these segments, so all of them that we're outputting is in fact a model and if it is a model then we can go ahead and choose which property that we want to output. Now what I'm doing is I'm assuming that each model that's inside of my breadcrumbs has
17:06
a slug which I'd assume it had and also I'm assuming that it has a title. I'll show you a tip in a minute that you can use to make this different depending on the different data you're outputting. But for now, this should be just about good and you can go ahead and modify it as you
17:20
need. So what I'm going to do is create inside of here a model method. And originally when I built this, I passed a type into here so we would call model like so and we'd go ahead and say category for example or article but that got a little bit
17:37
messy inside the view. So what we're going to do is take a little bit of a more proactive approach and we're going to go ahead and collect up this request root parameters like so. If I can spell that correctly, so let's say parameters.
17:54
And all this will do, we just die dump on this and we go ahead and call the model method from inside of here. So let's just switch this over to model for now. This will give us the following.
18:06
So that will give us all of the parameters that we have currently passed through into the request which at the moment of course are just the results of the root model binding. So we have category and article. Of course the only issue here is if you did pass something like ABC1 in, you are going
18:21
to get that. So if we come back to here and just get rid of that die dump, what we want to do with this is we want to collect these up and then we want to do a where. Now there's no danger in doing this because this isn't going to actually hit your database.
18:34
All we're doing is a where check on a collection. Still slightly slower than, you know, just not doing this but of course it's better than hitting your database. So like I said, I'm assuming that each of these has a slug and I'm going to go ahead
18:48
and check where the slug equals the segment that we've passed in. So let's just grab this out again and just do a file dump on this. Of course we're going to get a few nulls in here because not everything is a item. So we have, well, an empty collection we get just here.
19:05
But this one just here is our category and this one just here is our article. So this is plucking out the models if that is the case. All we need to do now is a first and of course what's going to happen is we're either going to get a null value, an empty value just here, or we're going to get the result of each of
19:24
these. So what we can now do is over in Breadcrumbs, call model. If that model doesn't happen to exist, we can then just fall back to the default of outputting the segment name.
19:35
And to do this, what I would typically do is just use the optional helper and then I would go ahead and access the title from that particular model. Or if that isn't available, I would go ahead and call the segment name like so. So now what we end up with is the following.
19:50
We get the title of the model, so title of tutorials as well. Again the tutorial slug is slightly different now, but we are specifically grabbing out the title. Now what you could do is, you know, if you wanted this to be a little bit more flexible
20:06
in terms of not always accessing the title of something, let's say that over in your article model the title was name or the category was name more appropriately, then you would of course need some kind of method in here. So let's say Breadcrumb name and you could go ahead and just return in here this and
20:26
a name for example if it wasn't this title. Since it is this title, I'm just going to keep it as it is. If we come over to article and also put this inside of here, we now have a common method inside of each of our models which means that we can return different things for different
20:42
models. So that's just a really common pattern. So in here we could just say Breadcrumb name or in this case it would be Breadcrumb value. That would probably make a little bit more sense and we get exactly the same result.
20:54
So of course there are downsides to this particular approach with Breadcrumbs. Like I said, check out that package that we discussed at the start of the video. But this is pretty much, you know, working for most cases as long as your URL reflects the Breadcrumbs that you want to use which to be honest should be the case anyway.
1 episode 21 mins

Overview

Build a partial to generate dynamic breadcrumbs based on your route structure, with plenty of refactoring along the way.

Alex Garrett-Smith
Alex Garrett-Smith
Hey, I'm the founder of Codecourse!

Episode discussion

No comments, yet. Be the first!