Playing
01. The Laravel tap() function

Episodes

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

Transcript

00:00
OK. So let's have a look at the tap function in Laravel. This is a really nice way to clean your code up if you've not seen it or used it before. And we're going to be looking at a couple of examples.
00:11
If we just head over to our API routes here, I've got a user's resource and a user's addresses resource. So the first example of this is going ahead and updating a user. If you wanted to update a user, of course, the first thing that you're going to have
00:28
to do is update that user. And if you're building out an API as we are here, you would probably then want to return the user. Now, of course, the tap function isn't limited to just controllers.
00:40
You can pretty much use this anyway. It's a global function within Laravel. So this is just an example. And you can go ahead and use it however you want to.
00:49
So I've got this open in Postman. I can go ahead and look a user up by their ID, pass in some values and keys and have this updated. So let's just head over to the command line and open Tynker.
00:59
I'm just going to go ahead and create a user in here for testing. This is the user ID 2. So let's go ahead and switch this across and go ahead and send this request across. Of course, it's not going to do anything just yet.
01:12
Okay. So let's go and put in the code that we'd usually use. So user update. And to keep things nice and clean, we could say request only name.
01:22
And of course, you can pass multiple things through to this. And then we would go ahead and return that user. So let's go and try this out. Send this request across.
01:32
And sure enough, we get back what we would expect. Now in this case, if you were just building an API out like this, you might think it's a little bit cleaner to just go and immediately return this. The only issue is the update method as well as any other methods that you might be using
01:46
in your app doesn't actually return that data. It actually returns a Boolean. So in this case, we have to do this. Now it's really not the end of the world.
01:55
If you're obsessively trying to clean up your code, then this is going to help you out. Otherwise, you probably won't care too much about the tap function. So let's first of all just open up the helpers.php file that comes with Laravel.
02:09
And let's take a look at the tap function. That's the wrong file. So let's go ahead and open up this one just here under helpers. Let's open this tap function and see what happens.
02:19
So we'll talk about higher order tapping in just a second. But essentially all of the tap function does if we just get rid of this temporarily is it allows you to pass a value in and a callback. The callback is invoked passing that value in and then we simply return the value.
02:34
So we do something with something we pass into here and then we return it. So it's pretty straightforward. So let's come over to our user controller and see how we could do this. Let's go ahead and return using the tap function, passing that user in and then going ahead
02:50
and using that callback just inside of here. And let's go ahead and take this value here. Go ahead and do an update on that user. And we'll get the user instance into there if you remember from that callback.
03:03
And that is pretty much it. So that is going to go ahead and do exactly what we've just done. Let's go ahead and test this out by sending this across. And sure enough we should see that updated user.
03:14
Of course we just need to go ahead and bring the request into scope here. We'll look at a slightly easier way to do this in a minute using a higher order function. And you can see that's worked. Let's just go ahead and switch that name over just so we can make sure.
03:27
And sure enough that is working. So we've essentially cleared this up into one line. This still isn't great though. So we can use a higher order function where we get rid of the function just inside of
03:37
here. And instead we just pass the value in and then we take in the value of that immediately returned from here. So let's go ahead and just do this and that would work in exactly the same way.
03:49
If we go ahead and just open up the helpers and open up that tap function again. If the callback is null, we return a new higher order tap proxy. Let's go ahead and open this up and we get a target in here. And that will go ahead and call any methods on there that we are using.
04:05
In this case updates. It will call that on the target and then it will return the target. There's just a couple of ways that you can use this. This was introduced I think in Laravel 5.2 and then more recently this.
04:18
Don't quote me on them but this was implemented first and this a little bit later on. So this will now work in exactly the same way. Let's just go ahead and switch my surname back so we get exactly the same result. Now let's take a look at a slightly different example.
04:33
You can see I've got this addresses route just set up here and we're not doing anything in here at the moment. If for example we wanted to post to that particular user and go ahead and send some data across, we can actually use the tap function to really clear up our controller.
04:49
This is going to be a massively over-optimized version of what you may already do. As your code base gets more complex, you might find the tap function helpful and I'm going to show you why this is helpful as well. So we're not just going to refactor, we're going to look at how this actually helps.
05:05
Okay, so first of all let's go ahead and just implement a store request here and I'll talk a little bit about how we're actually going to set this up. You can see here that I'm sending through a line one, so that's something that we would expect to store and I'm storing or passing through a country code.
05:20
Notice I'm not storing a country or passing through a country ID. So if we just look at the database here, we've got a country in here, so I've just got India. Let's just go ahead and switch that over to IN so we get the right thing and we over in our users table of course map this up to that particular user.
05:38
The reason that this might be useful is you might not have the ID available and you might just have the country code. So for example on the front end if you're pulling through a list of countries from another service you might just have that country code.
05:50
So what you might need to do is into the store request for that particular user only have access to that country code. So what you're going to have to do is a few things. Look up the country.
06:04
Of course the first thing you want to do is validate but we'll skip that just for now. Go ahead and create an address manually using new address. Then you'd have to fill it with the properties that you need. You would have to associate the country.
06:18
You would have to associate the user and you would have to go ahead and save the address and then return the address. Now what you can do of course is over in your address model set the country ID fillable and then fill that in.
06:32
But I don't really like doing this. I like associating models. I think the code ends up being that little bit easier to read and also easier to change a little bit later on.
06:41
So let's do this the traditional way then we'll work through refactoring this together. Potentially over refactoring this but at least we'll get a good idea as how we can use the tap function. So the first thing that I'm going to do is go ahead and pull out the country that I need
06:55
just using a simple where clause. So we're going to go ahead and say request country code and then go ahead and grab the first country. At this point we would have done a database validation up here so we'd know that this
07:08
country does actually exist. Let's just go ahead and die dump on that country just to make sure that we are getting that through and sure enough it looks like we are getting that correct country through so we can proceed to create a new address.
07:22
So I'd probably if it was me create a new address model like this, either pass in the actual dates that I wanted to store as part of that model directly into here or you can go ahead and use address fill, it's entirely up to you and then I would of course go ahead and from the request pull out the dates that I want to store.
07:40
In this case it's just going to be line one. What we then need to do is on the address using the country relationship which I've got set up just down here as well as the user, we'd go ahead and associate this. So we would associate that with the country that we've just plucked out of the database
07:57
and we would do the same thing for the user as well. This will just basically fill in for us the user ID and the country ID. So let's go ahead and associate that. Then we would go ahead and save this address and then we would go ahead and return that
08:11
address. So let's make sure that we've pulled in the namespaces for all of our models, that looks good to me. Let's go ahead and store this address and see what happens.
08:19
Okay, so perfect. We get back everything that we would expect from that. Now when I'm refactoring something, not necessarily something as simple as this, I like to look at what I'm doing inside of a single method.
08:32
So inside of here we're doing quite a few things as we listed a moment ago. We're grabbing a country, we're creating and filling an address with the data that we want to save, we're associating a country, we're associating a user, we're saving that address and then we're returning that address.
08:47
So this is probably as things start to get more complicated, particularly if you started to implement the ability to update an address, you'd want to go ahead and start to refactor this. So let's look at how we might do this.
09:00
I'm going to go ahead and comment all of this out so we can just reference it and let's see how we can make this a little bit tidier. So the first thing is probably a method to just go ahead and create a new address from the request data which will involve creating an address and attaching a country to that.
09:18
Probably see the country as part of the address and not something that the user owns. So I'd see the country as the actual address data rather than the user being as part of the address data if that makes sense. If it doesn't, it will do in just a second.
09:32
So let's go ahead and create this out, of course accepting in a request inside of here. And inside of this method, probably want to go ahead and just new up an address as we've already seen. We can go ahead and pass the data in to this.
09:46
So let's go ahead and say request only. And now in here, we could go ahead and type in line one. In this case, what I'd want to do and I realize we're kind of getting away from the tap demonstration but I'd have some kind of get address fields, get address fields from request and then I
10:04
would return an array from here so I can very quickly see exactly what this is and I can update them at any time. So I'd go ahead and pass this get address field into here and that just makes it a little bit clearer to see what we're doing rather than having all of that on one long line.
10:21
Now what I would do here is I would go ahead and return using the tap function, passing the address into here, having a callback and from that callback, remember we get the actual address itself. So we've created a new address instance.
10:35
And inside of this method, we could do something like associate address. The reason that it would be good to extract this out to another method is if we were updating an address, we'd also want access to some kind of associate address method inside of this controller.
10:52
So inside of here, we are going to just create this method out very quickly like so and this is going to go ahead and take in the address. In fact, this needs to be associate country of course. Let's go ahead and switch that over here as well.
11:07
So that's going to take in the address that we want to associate with and either the country or the request so we can go ahead and look this up. So down here, we want to go ahead and just say address, country, associate and then we want to go ahead and fetch the country by a code.
11:24
So again, I would start to extract this out to another method. Just a general rule I like to keep in mind is one method to do one thing. So associating the country would just associate a country. It wouldn't get a country and associate a country at the same time.
11:40
And this allows us to be a little bit more flexible with our code and reuse. So let's pass a code in there and pretty much do what we did up here, grabbing a country like so. Let's go ahead and just pop this into here and of course go ahead and return that.
11:55
It's going to go ahead and get that country by code so we can now associate this get country by code, passing in request and passing in the country code from the request like so. So this will associate an already fetched country and this will of course go ahead and just get the country.
12:13
So it's all doing one thing. So a couple of dot blocks here as well just to separate things out while we're here. And we'll do the same for this one as well. Okay.
12:24
So the next thing is now that we've associated the country, if we just go ahead and pass in the address itself and the request and of course because we're using a closure here, we just want to bring the request into here. We now want to go ahead and actually store this and then associate the user.
12:40
So let's get rid of all of this because we pretty much know what we're doing there. So for the store method itself, this is just going to be kind of a one-liner wrapped down. We're going to use tap again, this new address from request, passing in the request. That's going to go ahead and create the address and associate the country.
13:00
And then we're going to go ahead and create our closure in here which will give us that address back into here. We're going to go ahead and use the user that we're associating with this with. And then we're pretty much going to duplicate the pattern that we used here.
13:17
So we're going to say associate user and we're just going to pass in the user in place of the request. So let's come down and essentially just duplicate this method. Let's go ahead and give this a dot block and we're going to say associate user.
13:34
Let's get rid of this while we change the signature over. That's going to be the user. And then of course what we do is we say user associate user. So then if we are doing anything else with an address, we also now have access to an
13:49
associate user function so we can keep things nice and simple. Okay, so let's go and make sure that this is all set up correctly. Let's just run this and see if we've made any errors. Okay, so we've got an undefined variable request which of course if we just come down to 63.
14:10
Yes, of course we just need to switch that over to code that we're using in here now. Okay so there we go. You can see that's worked in exactly the same way. Now of course what we've done is created a whole lot more code that we had originally.
14:25
But you can see now looking at this store method, we're saying, well, we're creating a new address from the request and then we're associating the user with that. If we come down to new address request, we know that we're creating a new address using the address fields, going ahead and tapping the address and associating the country.
14:42
And then we have all of these kind of small helper methods as well. It is a lot more code. It's a lot more code to write. But personally looking down this controller now, each of these methods has a single job.
14:54
And we've actually made this simpler using tap. We don't have to use tap here but it just makes things a little bit shorter. And when I see tap, I think we're doing this with this. So it makes me immediately read this a lot more fluently.
15:07
So again, a really simple example, let's just go ahead and duplicate this and we're going to say update and we're going to go ahead and update the user's address. So we're also going to get an address into here. And what do we want to do?
15:22
Well, we want to tap the address. We don't need to associate the user because of course that's already going to be associated with that user. But we can use associate country to associate a new country with this if we want.
15:36
So we can say this, associate country, pass the address in and of course we need to bring the request into scope here and we're just going to go ahead and pass that request in. Remember associate country will deal with plucking out the address for us. And of course inside of here, what we're going to do is say address fill and remember we
15:54
already have the get address fields so we can really simply say request only this get address field. So that's updated that. It's associated the new country and then we can say address save and that's going to go
16:10
ahead and return the address to us. So what we've essentially done is not had to duplicate all of the lines that we originally had in here just to update an address again. So let's go ahead and test this out just while we're here.
16:22
So we are going to pass in the address ID and make a patch request. Let's go to the database and just check that address out. So it's ID of one of course. And let's go ahead and send one, two, three, let's say one, two, three, four code street
16:39
and let's change the country over here as well. So let's duplicate this down, set this to GB and save that. And let's go ahead and send this request across with GB in here. Send that.
16:55
That has now been updated. We've updated the line one. We've updated the country of course. And we've got a little bit of an issue here where the user ID is now being filled in and
17:05
it's not actually giving us back the full user. And that's because we haven't reassociated the user with this. Let's just go ahead and do this now. So we're going to say associate user and we'll go ahead and pass in the user here.
17:21
Bring that into here. And of course pass in no request to that as well. So let's bring that down. Send this across again and just go ahead and pass of course the address into there also.
17:36
And there we go. So that has successfully updated the user in there. Now the other way that you could do this if you didn't want to go ahead and reassociate the user because the only thing that we really need to change across is the country.
17:47
You could go ahead and load in the user as you do this. So you could down here say address load user. So we're doing eager loading. Send that across and we get exactly the same thing.
17:59
So you can either reassociate it so when you return the updated address, you're going to have that user model in there or you could just go ahead and load the user in like this. Not for everyone. And again, we've over optimized something that didn't really need to be optimized.
18:15
It's a good start just to kind of understand how you can just really clean things up with tap. Of course there are so many other uses for this. This is really the only one I could think of.
18:25
So there we go. A really simple way just to go ahead and use tap. The most simplest way, the way that you'll probably use this the most often is just doing stuff like this.
1 episode 18 mins

Overview

Let's walk through the Laravel tap() function, and how it might help clean up our code.

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

Episode discussion

No comments, yet. Be the first!