If you're like me, you'll find that as your project gets larger and more complicated, you naturally outgrow the default structure of a Laravel project. So in this snippet, I'm going to talk to you about just switching things around a little
00:13
bit just to make this a lot easier to maintain going forward for medium and large projects. So the inspiration from this was taken from domain-driven design, but we're not going to be talking about domain-driven design. This is just really a kind of structural inspiration from DDD.
00:33
So let's start things out. I have a completely fresh project. I'm going to go ahead and give my app a name. First of all, this is really, really important because we don't want to have to be manually
00:43
changing around too many namespaces. So let's go ahead and give this the name CoCourse. Of course, that makes sense. I'm working on a CoCourse project.
00:51
Okay. So inside of our main app directory here, we've got console exceptions, HTTP, providers, and then, of course, as we know, the user models just float around in the app directory. Now we're going to start things off by creating another app directory, which might seem strange,
01:07
but just bear with me, and we're also going to go ahead and create a domain folder. Of course, this is where the inspiration from domain-driven design comes from. So HTTP, we can leave. We're going to leave that one in there, but what we're going to do first of all is move
01:22
over, so I'm going to come over to my file browser, I'm going to move console over to app. We're going to move exceptions over to app, and we're going to move providers over to app as well.
01:32
So essentially, what we're only going to have in our app directory is an app folder, a domain folder which is currently empty, of course, and an HTTP folder. Now essentially, we'll talk more about this a little bit later, but app is where everything goes that doesn't fit into a particular thing within your application.
01:51
Inside of domain, we're going to be creating folders like users, authentication, courses, forum, any kind of domain within your application. Everything will go within one folder. So the next thing that we're going to do is just tidy things up, because of course at
02:05
the moment, what's going to happen is we're going to see a 500 error just because some of the namespaces aren't quite right, so we're going to change things around. First thing to do is come over to bootstrap an app and just start to change the namespaces around here.
02:18
The kernel is fine because we kept our HTTP directory, but we know now that the console folder is inside of the app directory, the same for exceptions as well, so we can switch that up as well. Now it's still not going to quite work and that is because, of course, we've moved things
02:33
over to our app directory, so we're going to need to update the namespaces for each of these as well. So this can get a little bit annoying, but let's just go ahead and quickly update these and we're going to need to do this for all of our service providers as well.
02:45
So let's just go ahead and replace them. If you're great with a text editor, you could just go through and do a find and replace on all of these. Okay, so let's give that a refresh and we're kind of back to a point where we're not seeing
02:57
any PHP errors, but we are seeing some errors inside of here. So the next thing to do is go over to our config and app and update this. So let's switch over to config app and, of course, because we have our service providers moved now, these are no longer inside of a base providers folder, so let's switch these
03:16
ones up as well. So this is a little bit annoying, but you could save this base structure if you wanted to just so you have it for future. So that's pretty much everything done now and working.
03:25
Next thing is we're going to make authentication and we're going to migrate our changes. So let's do a make auth, wait for the scaffolding to be generated, and let's do a migration as well. I've already switched over my database credentials, so this is just now giving us authentication.
03:40
Let's give that a refresh. That's cached from another course and we can go ahead and register an account. So let's just do this really, really quickly just so we're in and we can see this working. And it looks like everything is working as we'd expect at the moment, but we have a few
03:55
more structural changes to make. So let's go ahead and make these now and fix things up along the way. So the one thing is the user model. We don't really want models floating around in the main directory because you can have
04:05
a huge list of these as your project grows. So of course, inside of the domain, this is where everything under a certain domain goes. So you could put this under auth, you could put this under users. It's really entirely up to you.
04:17
There's no hard and fast rule for this structure. It's just something that I've been using. So I'm going to go and I'm going to create a user.php model over here and I'm going to go ahead and copy and paste this over here.
04:28
You could even put that inside of a models directory if you wanted to, but I tend to leave these just floating around here. So this, of course, now is in co-course domain users. So anything to do with the user will now go inside of this directory.
04:42
You could also have a domain for auth as well, so anything to do with authentication could go in there. Of course, you can mix users and authentication together if you wanted to. So now that we've moved that model, of course, what we're going to see is a problem.
04:53
So let's go ahead and log out and let's go ahead and try and log in again. As long as we've deleted this user model because we don't want that anymore. Let's go ahead and sign in. And of course, we see an error.
05:04
Now if we come over to config and auth, this is where we register the model that needs to be used by default just over here. So we now know that this is in co-course domain users, and that's using the user model. So let's give that a refresh, and sure enough, we're signed back in, and this is now working.
05:21
Now for registration, this is also not going to work. So if we head over to the default register controller, which will be under HTTP controllers and auth, we just need to come down and switch over the namespace for this when our user is created.
05:35
So let's just go and pull the namespace in using the plug-in I have in my text editor. So that's pulled that new namespace in. So now we should be able to register a new account. Let's just go ahead and delete this user, and I'll re-register as myself.
05:50
Let's go ahead and enter all of my details, and we are successfully in, and that's working. So we'll talk more about the domain a little bit later, but what we want to do now is kind of keep a similar structure to our HTTP directory. So what I want is inside of HTTP, I want the same thing.
06:07
I want users, and I want auth inside of here. So I want everything kind of separated by domain. Now that means that we need to start moving our controllers around. So let's go ahead and do this now, and of course, things are going to start to break.
06:21
We'll talk about our base controller as well in just a second. So inside of HTTP, we have auth. So let's go ahead and grab the auth controllers. Let's just copy these.
06:34
You can, of course, do this in the command line and move these over to here. In fact, we're going to put these inside of a controllers directory under HTTP, and I'll tell you why in just a second. We'll review this structure in just a minute.
06:44
So we've copied over our auth, and home could probably go in its own folder. Let's go ahead and just put this inside of a kind of home directory, although technically that's the dashboard, so it could go under users. It's entirely up to you.
06:56
And again, we're going to create a controllers directory, if I can spell controllers correctly, inside of that. So it's nicely tidy. So what we can do now is get rid of our main controllers directory, and we can leave middleware
07:09
and our kernel inside of here, because middleware generally applies to lots of different requests. So I prefer to keep this in its own folder. So let's take our base controller, and we'll speak about this structure in just a second. And let's put this over an app.
07:23
You don't need to do this. I'd see it as a kind of almost abstract class that we just extend, so I prefer to put this inside of the app directory. So let's go ahead and create a base controller file here.
07:37
Of course, we want to change the namespace over for this, so let's just reopen this up and pull the namespace in. And of course, that needs to be co-course app controllers. And now what we can do is just delete that controllers folder that we moved everything
07:50
out of. So let's just talk about this before we go ahead and update the namespaces. We've got now an app directory with all of our kind of abstract stuff in, our console stuff, exceptions that might apply to everything in our application.
08:02
We have everything separated by domain, e.g. at the moment just our models, but we'll talk more about what we can put in domain in just a minute. And now we have an HTTP directory with home, our home controller, auth, and our auth controllers, and users, and anything that we want to put in there, as well as our kind of general middleware.
08:19
So of course, at the moment, this isn't going to work, so I'm going to go ahead and switch over all of the base controller namespaces for here. So let's go ahead and do that. In fact, I'll just very quickly do this just so I don't take too much of your time off,
08:31
and I'll be back with you in a second. Okay, so I've switched over all of the namespaces for the base controller inside of here. Of course, what you're also going to need to do is change around the namespaces inside of here, because at the moment we have HTTP controllers auth.
08:47
Now the whole point of this structure is we're moving this around so it's easy to find each section of your application. So it's not controllers and auth, it's auth plus anything else we have, and then controllers. That's pretty much the kind of structure we're going for.
09:01
We're separating everything out in our application by its domain so we can easily find that inside of a folder, rather than having it the opposite way around and having one models folder, one controllers folder, with all of the different sections inside of that. So let's go ahead and switch this up.
09:17
This, of course, is now app HTTP home controllers, and that should be just about it. We are going to see some errors, so let's give this a refresh. And of course, we see home controller does not exist. Now of course, that's the case because if we just open up our roots and web file, we
09:32
have a reference to home controller. This was previously just inside of HTTP and controllers. Now to fix this up, if we come over to app and providers, and instantly this feels better to me because I know that app contains everything in my application that's things like providers,
09:47
you know, so I can jump straight over to app and start to change things around. We're going to come over to our root service provider, and of course, co-course HTTP controllers doesn't exist anymore. We need to reference the namespace, the base namespace for all of our controllers as co-course
10:02
HTTP. It might seem strange, but what this means now is we can say app home controllers and then home controller. And this might seem a little bit long, but if you couple this with namespaces inside
10:16
of root groups, this does work really nicely. So you can see that this is now working as it should do. Now the other issue with this is if I now try and log out, of course the HTTP auth logging controller doesn't exist.
10:29
Now this is a little bit more of a problem because when we go ahead and make auth within Laravel, we have an auth routes method which is called. And if we just go ahead and open up the router, like so, and this needs to be illuminate routing router, the auth routes are actually registered all over here.
10:46
Now I think it's a good idea anyway to move these out so you have a little bit more control over the naming of these, the locations to each of the controllers. So I'm going to copy these and I'm going to paste them into here. And of course I'm going to get rid of the root registration just here.
11:03
So let's just tidy this up because of course at the moment we can't reference this within a plain file. So let's go ahead and open up a find and replace inside of here and let's replace this out with root, like so.
11:14
Let's go ahead and do a replace all on this. And of course we also need to replace over the location of these as well. But let's make it easier for ourselves and put this inside of a root group with a prefix as well.
11:26
In fact, we don't really need a prefix, just a kind of common namespace for each of these. So we now know that over in our HTTP auth, we have controllers and then all of these. So what we need to do is say auth controllers and that is the namespace for each of these. So let's go ahead to find out our closure and let's go ahead and place all of these
11:47
inside of here and go ahead and indent that as we normally would. So we just need to get rid of auth slash. So let's go ahead and just do a quick find and replace on this with nothing and of course just fix up that because that was removed as well.
12:03
So what we should now have is the ability to sign out properly and we can go ahead and register. We can log in. We can do pretty much anything we would normally do and we now have a little bit more control
12:12
over our authentication root so we can change the names over for these as well if we want to. Now that pretty much wraps up changing the structure of this over. What we're going to do now is talk about where we're going to put certain things because
12:24
that's the whole point of this. So let's just review each of these just before we move on. So app is going to be the place where you place any abstract classes, any services like third-party service wrappers that might apply to each, you know, every domain of your application.
12:40
If they're very specifically tied down to a domain, you can put them inside of the domain folder. You know, it's entirely up to you how you structure your project but this should give you a really good start.
12:49
So of course over in the domain, this is going to be anything to do with any section in your application. So for example, you might have a forum. So you'll have a forum domain.
12:58
This will contain all of your forum models, forum events, forum listeners, anything like that. And of course, you know, the list goes on. You could have pretty much anything inside of here.
13:09
I won't give any more examples because that should be pretty clear. Now let's just head over to the command line because the problem that we will now face is when we do something like phpArtisan make model and I always use Artisan to create models. Sometimes I copy and paste previous models but, you know, this is the easiest way to
13:27
get a model created, a controller created, an event or a listener created, a job, a console command, you know, you name it. It's a much easier way to do things. The only problem here is we're going to have to now provide the full namespace to where
13:41
we want to place this. If I wanted to create, say, a country model to represent each user's country, that's going to go ahead and successfully create that but it's going to place that back in our app directory. Now that might be fine.
13:53
You could just copy and paste this and go over to domain users and create a new model in there if you wanted to. But the easiest way to do this would just be to provide the full namespace from the start.
14:02
So let's go ahead and pull this back again. Let's just go ahead and say co-course domain users and country like so and that will go ahead and place that in the correct place for us. If we just come over to users now under domain, we now have that country model with the correct
14:16
namespace. So, you know, it's a little bit more annoying to use Artisan. I can't find an easy way to fix Artisan to specify this path. I'm sure there are packages available that allow you to conveniently do that but for
14:30
now, you know, it's, you know, just adding in the full namespace. So like I said, commands, things like console commands will go inside of apps. You're going to need to do a very similar thing here. You might need to say make command and you're going to have to say co-course app or the
14:45
name of your project, console and then you might want to put this in the commands directory and you might want to go ahead and sync something and have that as a command. So that's going to go and place that. If we go ahead and just pull in and escape that slash, that's going to place that in
15:01
the right directory. Let's go ahead and get rid of that one. And there we go. So we've got console command sync something.
15:08
Now the other thing is things like third party services, these could go in app like I already said or if they were specific to a domain, you could put them inside of each of these folders. Let's look at another thing.
15:18
So things like events and listeners as well. So let's say that a user successfully registers. Well, let's go ahead and make an event in here called user was registered. So let's put this under co-course.
15:29
I already know that this is going to go under domain and it's going to go under auth and I'm going to put this under an events folder. So user registered for example and then I might want a listener for this. So this would go under listeners and this would be something like send a welcome email.
15:46
So send welcome email and of course that might go ahead and send an email class if you're using Laravel mailable classes. That would of course go inside of domain as well because it's to do with that particular thing.
16:00
Let's go ahead and make that listener very quickly and just take a look at the structure that we have here. So we've got auth events user registered, events listeners, everything to do with authentication now goes under here.
16:11
Hopefully by now you get the idea. Now what I want to talk about is the new HTTP folder or the new structure to the HTTP folder because this is slightly different. What kind of things would you place inside of HTTP?
16:23
Well the rule of things like this, let's say we have a transformer and we're building an API and we want to transform some data. The rule of the HTTP directory at least for myself is think of the responsibility of say a transformer.
16:38
It's for giving you an HTTP response so put it in the HTTP directory. The structure is the same. This of course stays in HTTP because it's listening to an HTTP request and doing something either redirecting or allowing the user through.
16:51
Form requests as well if you're used to using the Laravel form requests would also stay in the HTTP directory because they look at the HTTP request that you've made to your application. So in this case the structure would be something like say you had an auth directory, you would
17:05
have say your form requests over here and you might have a form request to register a user. So you might be switching up the validation to use a form request. So you might say register store form request, you know, whatever.
17:20
Now transformers like we've said will also go in HTTP. That's pretty straightforward and things like exceptions you could place either in domain if they're very specific or you could place them over in your general app exceptions directory. Now this might seem pretty straightforward but give it a go.
17:35
It's one of these things where you make a very slight change and it has a huge amount of impact. For me I've been using this structure for a long time now and it's worked out really, really well to just separate things out.
17:47
I know exactly where I need to go when I need to, you know, create a new kind of user model. I need to create a policy for users. I would put that in domain. If I need to create a transformer I would come over to users.
17:58
Perhaps we have some kind of user's profile. I would put a profile transformer over here. I would put a normal user transformer over here and so on and so forth. If I was building out a forum of course I would have a forum folder inside of here.
18:11
I would have controllers inside of here. I would have my form requests. I could just call that requests if I wanted to. I would have transformers over here and I know, well, a controller belongs to an HTTP
18:23
request, a request does and a transformer responds to a request so I put that all in HTTP. So hopefully that gives you a good idea. This isn't a hard and fast structure but it's a much easier way to organize your application
18:36
as it scales. Plus it hasn't taken that long to set up. More of this has been me talking and explaining so we're not investing huge amounts of time thinking about the structure.
18:45
We're just giving each part of our app its own place to live and not mixing things up. So feel free to change this up and do what works for you but hopefully for you this is a good starting point. I guess it would also be a good idea just to show you around the structure of the new
19:01
Cocoa's API. So as you can see, I have a pretty much similar setup to what we've just looked at. The app directory over here is exactly the same. But of course when I open this, I have app domain and HTTP much like we've discussed.
19:15
So inside of app, I've placed things like listeners for general things. So in this case, flushing out cache for transformers, things like filters as well. So filtering functionality, I've got abstract classes over here and also things like services. So third-party services like a drip service which goes ahead and pushes information up
19:35
for mailing lists. Also things like support as well. So a duration format of courses. This just goes ahead and lives over there as well because it doesn't necessarily belong
19:45
to any particular domain. So over in domain, as you can see, I've got each section of the site just over here including the repositories. You can see if we look at the comment section that will be new under each video.
19:56
We've got events, listeners, notifications as well to go ahead and notify users that a new comment was posted. Repositories as well also are going under domain. So I have a comment repository here.
20:08
Now of course a comment repository just, well, that's an interface. But for the eloquent comment repository, this just implements the comment repository interface which is over in this folder. But the repository abstract that this extends is over in the app folder because it belongs
20:24
to lots of different things. So we wouldn't want to put that inside of a domain and mix that in. And the same for all of these as well. So you can see I've got course feeds, filters, repositories.
20:33
These are the specific filters that apply directly to each course. So over in HTTP like we've already looked at, we've got things like let's pick something interesting like courses. We've got a list of course controllers in here.
20:44
So a course comment controller, a course comment reply controller, and a base course controller. I don't know what that is but I'll fix that up later. We've got requests as well. So to store a comment for a particular course and transformers as well.
20:58
So a part transformer just inside of here that transforms the details for each part. So that is pretty much it. I can't really explain much else. That's a really nice structure that I've been using for a long time now and it's just worked
21:11
out really well. As things scale, things don't get messy and it just works nicely. So there we go. A really simple example of the CoCourse API and how I've structured that.
1 episode• 21 mins•7 years ago
Overview
You'll quickly outgrow the default Laravel structure as your app grows. Without much effort, let's look at some small changes that'll make a huge difference.