This episode is for members only

Sign up to access "Laravel Teams" right now.

Get started
Already a member? Sign in to continue
Playing
36. Building a helper to access the current team

Episodes

0%
Your progress
  • Total: 4h 36m
  • Played: 0m
  • Remaining: 4h 36m
Join or sign in to track your progress
01. Introduction and demo
4m 49s
0%
02. Setup with Pest
4m 2s
0%
03. Building the user teams relations
6m 5s
0%
04. Creating a personal team when registering
6m 3s
0%
05. Leaving all teams when an account is deleted
3m 55s
0%
06. Tracking the current team
4m 50s
0%
07. Showing team details in the UI
2m 55s
0%
08. Switching to another team
7m 24s
0%
09. Authorising team switching
6m 53s
0%
10. Updating a team name
10m 48s
0%
11. Basic roles and permissions setup
5m 26s
0%
12. Team roles and permissions middleware
9m 18s
0%
13. Authorising current team updates
3m 43s
0%
14. Testing team permissions through HTTP requests
3m 58s
0%
15. Leaving a team
10m 50s
0%
16. Displaying team members
8m 42s
0%
17. Making team members look better
5m 3s
0%
18. Removing a team member
15m 18s
0%
19. Preventing self removal from a team
4m 7s
0%
20. Storing invitations
13m 31s
0%
21. Validating invitations
6m 38s
0%
22. Authorising team invitation creation
6m 22s
0%
23. Displaying invitations
3m 16s
0%
24. Revoking invitations
12m 46s
0%
25. Sending an invitation email
13m 6s
0%
26. Accepting an invitation
12m 22s
0%
27. Displaying a modal to change a member’s role
10m 31s
0%
28. Updating a member’s role
9m 5s
0%
29. More authorisation and checks for role changing
10m 14s
0%
30. Fixing up the email sending test details
49s
0%
31. Fixing and validating email addresses for invites
1m 32s
0%
32. Tidying up @can directive checks
3m 25s
0%
33. Detaching roles when removing users
5m
0%
34. Adding an extra layer of protection to the team middleware
6m 35s
0%
35. Getting related models through teams
5m 37s
0%
36. Building a helper to access the current team
10m 47s
0%
37. Getting all related models through all teams
7m 15s
0%
38. Creating new teams
13m 7s
0%

Transcript

00:00
As I mentioned in the last episode, it's going to get really annoying every time we want to access anything within the scope of the current team to have to say request user current team and then the relationship that we want to access. Let's go ahead and make this a little bit more convenient.
00:17
So to do this, let's start with the request object. Now if we just open this up, you'll notice that we have the macroable trait added to this within the Laravel framework. What this means is that we can add our own methods to the request object, which means that we could create a method like team, which would just return the currently authenticated users current team.
00:41
Let's go ahead and do that now, then we'll go ahead and look at an even easier way to do this to have it just as a function and we'll write some tests alongside of this to make sure that it returns the right thing. Okay, so how do we create a macro for any macroable thing within Laravel? Well, we head over to any of our service providers. In this case, we'll just use our app service
01:02
provider and we go and choose the object that we want to add this to. In this case, it's Illuminate HTTP request. You can see already we've got the macro method here that we can use. This requires a string for the name of this, which will be the function that we call and the closure, which gives us whatever we want to be returned. So let's go ahead and just call
01:24
this team. We could call this current team, but let's try and keep things as short as possible and let's go ahead and create out that closure. Now inside of here, what we can do is we can just continue to access this, which references the request object. So if we think about it, usually we'll be doing something like this, request user current team. So we want to return this user
01:48
current team from here, which is the same as doing a request user current team. So in here, let's say this user current team and we're pretty much done. Now there's a couple of things that we need to check around this, like if the user isn't actually authenticated. We'll do that in a minute as we write our test, but let's just make sure this works. We'll write a quick test for this because
02:07
this is slightly different and then we'll go ahead and add the others. Okay, so now what we can do is we can say request team projects. That looks a lot better. It kind of reads better because we already know what this is about and if we head over, you can see we get exactly the same result. So adding macros like this, particularly in applications where you have something within
02:30
the context of something like a team, can be really helpful. Okay, let's go ahead and write a test for this. So let's say phpArts and test test and let's put this in a request directory and call it team request test for specifically testing this request macro that we've built and we're going to add this as a feature test, not a unit test, just because I'm going to be
02:51
creating stuff in the database. You can create this as a unit test, but I generally don't with this functionality. Okay, let's open up that request test, that team request test, and what do we want to test here? Well, we're going to test that it can access the current team through the request or whatever you wanted to say. Let's get rid of all of this because we're not going to be making an
03:15
HTTP request here. Now this test is actually going to be pretty simple. What do we need? Well, we obviously need a user, so let's go ahead and use our user factory to create this out and like I said, you can create this as a unit test and not actually physically create the user in the database, but since we're kind of relying on our user observer, there's nothing wrong with writing a
03:34
feature test like this. Okay, so what do we want to expect here? Well, let's go ahead and use just directly an expectation within PEST. Let's use the request helper or we could use at and request resolve request out of the container. It's entirely up to you. I prefer to use request here and what do we want to test? We want to test what's returned from team is an instance of a team model, so to the
04:00
instance of and team. Now, of course, we also want to check that this returns the correct team, which is the user's current team. We'll do that in just a second. At the moment, this test is not going to pass. Let's go ahead and run our test here, this team request test and see what we get. Okay, so you can see here we've got attempt to read property current team on null. Now the reason for that is
04:23
at the moment we've created the user, we're trying to access this within the request, but we are not authenticated here. How do we authenticate? Well, previously what we've been doing is using stuff like acting as user. That's not going to work. This only works in the context of when we then want to go ahead and post down or get a specific page. If we go ahead and run this test again, you
04:46
can see it still fails and that'll be for the exact same reason. Now instead, what we want to do is kind of work out when you are testing things, you can head over to whatever you're trying to do. So in this case, it's the request object. If we just open this up in our all places here, so it's this just here, let's go ahead and look at the user method and actually see how this gets resolved.
05:10
And you can see here it uses this getUserResolver. Now the user resolver can be set within this class. So if we just look at setUserResolver, this just basically tells us what gets returned when we try and access a user, which we're doing within that macro. So what we can do is we can say request and setUserResolver. This takes in a callback here and then we can just return whatever
05:34
we like. So let's go ahead and bring that user that we've already created into scope and let's just really simply return that user. So now inside of this part of our test, when we try and access that team over in our macro, this user is going to be this user here. Okay, let's run that test again and see what happens. And sure enough, this pass is great. Okay, so we can also add to this test. So
05:59
we could also say and, and then we can just start to chain on the ID. So we can make sure that this ID is the user's current team ID. We can either do current team ID like that or access it through the relationship. Let's go ahead and run that. And yeah, in this case, we don't actually need the and because we're continuing to chain on from the result of this and this return value, we can just
06:23
directly access the ID of the team from here. And let's go ahead and run that again. And yeah, sure enough, we get green. So that is now working. Now, the other issue is that if we're not authenticated at the moment over in our app service provider, this is going to try and access a relationship on a null. So how do we get around this? Well, let's go over and write a test for this. So let's say
06:44
it returns null if no user or if user is not authenticated. What if we want to do? So in this case, we don't even need to create anything. We just need to expect that if we're not authenticated in any way, then the request team is null. So we can just use to be null here. And let's go ahead and run that test again. That should fail because we actually get an error rather than a
07:12
null value returned. So how do we fix this? Well, if we come back over to our app service provider, there's a couple of ways that we could do this. We could write a defensive if statement. So we could say if not this user, then we want to return null specifically. So we know that we can't access that. And that should make that pass. Or if you didn't want to do this, you could use a null safe
07:34
check on this like that. And you could get rid of this if statement. And that would have exactly the same effect because current team would just return null. So let's go ahead and run that again. And we get green. So either of them options are absolutely fine. But we want to make sure we protect that. Okay, now we've got this functionality down. Let's talk about an even easier way to do
07:55
this. And let's start over in our dashboard controller to see what we might want to do. What we could do is just ignore request altogether. And we could say, well, we just want to run team projects, that would be a super convenient way to access the current team that we're in the context of. Now, obviously, this isn't going to work at the moment, we don't have a test specifically for
08:16
this. But you can see that we don't have a function called team that kind of makes sense. So let's go ahead and create a global function that basically just returns what we have from our request macro. Now to create a global function, we're going to create out a PHP file within the app directory, you could pretty much put this anywhere. And we're just going to call this
08:34
helpers dot PHP. Inside of here, we want to first of all make sure that there isn't already a function defined called team. So we're going to say if not function exists, team, this is just the kind of standard way to do things when we're creating out this kind of functionality. So we want to say function team. And what do we want to return here? Well, we want to return from our
08:57
request object, again, either using the request function itself, the helper itself, or app and request. And then we just want to return request team. And that's pretty much all we need to do for this. So that should work, we haven't registered this function yet. So it's still not going to work entirely. But to register this function out, we just need to go over to composer dot JSON,
09:18
and auto load this in underneath here. So we've already got our PSR for auto load stuff. But we can just add a list of files that we want to auto load from. And that's going to be app and helpers dot PHP. Once we've added that to there, we can go over and run composer dump auto load, optionally passing through the optimize flag. And that should go ahead and register that file
09:39
with composer. And we should now have access to it anywhere in our app. So you can see that this now works. Okay, so we could write a really quick test for this as well. So let's go over to our team request test, although it's not specifically to do that request, but it does still access it. And we're going to say can access the current team through the team helper function,
10:02
or something shorter if you prefer. So we pretty much want to do the same thing that we've done here. So let's go and just grab all of the content from our first test. But let's just switch this over. So all we want to do now is expect that the team function is an instance of team. And we want to make sure that the ID that's returned from the team function, which should be the current user's
10:23
ID is the user's current ID here. Okay, let's go ahead and run that test again. And we get green on all three. So there we go, we now have a nice convenient way to access the current team either directly through the request or using this helper function. And you can use this anywhere in your project now to access anything within the team that we're currently in.
38 episodes4 hrs 36 mins

Overview

Need team functionality in your Laravel application? Let’s build it from scratch.

We’ll cover the basics of creating teams, switching between them, sending secure team invites by email, and managing team members.

Powering everything will be roles and permissions for each member, with the ability to switch roles directly from your team dashboard.

Once you’re done, you’ll have mastered team functionality in Laravel.

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

Episode discussion

No comments, yet. Be the first!