Workshop Overview0:08
Hello everybody. My name's Jeffrey. We, and welcome to the Laravel Workshop. Alright, so real quick before I get started, let's get our ducks in a row. Let for section one, Simon was responsible for the static HTML and CSS build for a fictional social media app called Pixel. Alright, for section two, Jeremy then converted that into a traditional Laravel application using Blade files.
that into a traditional Laravel application using Blade files. Alright, so now for section three I'm gonna take the reins and I'm gonna show you some steps you might take in order to convert a traditional application into a fully functioning SPA. So I really do hope you're excited. Let's get going. Alright, so here you can see we have the GitHub repo pulled up for the workshop. And the most recent commit, of course,
Cloning and Installing0:51
repo pulled up for the workshop. And the most recent commit, of course, was the last one buying Jeremy. So I'm gonna go ahead and install this on my machine. git clone, I'll cd into that and then open this in my editor. Alright, here we are. But now a quick little note, whenever you clone a Laravel project in this way, well there's a handful of commands you need to run.
whenever you clone a Laravel project in this way, well there's a handful of commands you need to run. For example, notice in my sidebar, we don't even have an .env file. We haven't yet generated an application key. We don't have a a database SQLite file. These are all things we need to take care of. So I'll show you a little tip. If I open up composer.json, and we scroll down, well,
If I open up composer.json, and we scroll down, well, when we use composer create-project to whip up a Laravel project, this is automatically going to fire. And you'll see that it generates a key, it sets up our database and it runs our migrations. Now, in our case, that didn't fire automatically, but of course if you want you can run these commands individually or you can just run, uh, this composer script manually like this.
individually or you can just run, uh, this composer script manually like this. First, before I do anything at all here, let's install our composer dependencies and then we'll do the same thing for NPM. All right, next I will copy that .env.example file into .env. Okay, so now I can run composer run and I'll paste in that script. And yeah, once again, it will generate the key.
and I'll paste in that script. And yeah, once again, it will generate the key. It'll prepare the database and it will run our migrations. That looks good. Okay, so now let's see how we're doing. Can we view this in the browser? Yep, I see the splash page very good, but actually one thing that has occurred to me if I switch back is, well, we haven't booted up our vet server, so let's do that now from the terminal, I will run vet,
Reviewing Application Routes2:36
we haven't booted up our vet surfer, so let's do that now from the terminal, I will run vet, and now if I switch back, I wonder if anything will change. And yeah, we can see that pixeled font seeping through. So we are pulling in, uh, some of those custom styles. Excellent. Now, typically when I am introduced to a new code base, the very first thing I do is visit the routes file. If you think about it, this tells me what the application can do and what it can respond to.
If you think about it, this tells me what the application can do and what it can respond to. So immediately I can see, all right, we have a homepage and then I see these dev specific endpoints for login and log out. What I think I'm seeing here is maybe they haven't yet implemented the traditional authentication forms and instead they, they have some helper endpoints to quickly sign in a User for the purposes of, uh, local development.
to quickly sign in a User for the purposes of, uh, local development. This is totally fine. Just remember though, this can never, ever, ever enter production. So you might just want to remember, get rid of that after you build the forms or you can add a second layer to ensure that only on the condition that we are in a local environment do we, uh, generate these routes.
that we are in a local environment do we, uh, generate these routes. And yeah, maybe that would be, um, a safety, uh, precaution to implement. Okay, next, if the User is signed in, we have a homepage and it looks like he's using the term PostsController to represent, uh, basically the feed. Okay, next you can post to post to create a new post, you post to post to create a new post. Uh, next we have, uh, some scoped routes.
to create a new Post, you post to post to create a new Post. Uh, next we have, uh, some scoped routes. Uh, scopeBindings just ensures that, for example, this relationship is properly associated with this relationship. Uh, it just makes sure they match up. You don't want a situation where like for this User, uh, access their replies, but the Idea of the reply, they're you're accessing doesn't actually belong.
but the Idea of the reply, they're you're accessing doesn't actually belong to the User, right? So scope bindings forces, uh, those relationships. Alright, so we have profile handle. I'm assuming handle refers to like your username. Basically, uh, my handle on X is Jeffrey way one word, but my name is Jeffrey Jordan. Way, right? I think that's probably what that is. So I'm thinking he's saying if you make a Post
Way, right? I think that's probably what that is. So I'm thinking he's saying if you make a Post to Jeffrey Way status and then maybe the Post and reply, this is how I would reply to a Post. Maybe remember you can create Posts, but then you can reply to Posts. So it looks like that's the endpoint. Looks like we have an endpoint to retweet effectively or repost. All right? Um, this is one
retweet effectively or repost. All right? Um, this is one for quote tweeting I assume or quote posting. Um, this is for deleting a post. Okay, this is fairly standard stuff. Uh, this is one for liking a post and unlinking we're just using POST request there. And let me see, I'm PostController. So this is fairly traditional. Uh, some of the forwarding formatting I don't love here.
So this is fairly traditional. Uh, some of the forwarding formatting I don't love here. This is kind of javascripty, which, which Jeremy loves, but I'm probably going to normalize this a little bit and that's okay because it's my business and it's my project and I'm taking over here. Uh, but yeah, in real life if you're contributing to a project, just stick to whatever standard they have in place. Uh, but I'm gonna ignore that. Uh, next store reply.
to whatever standard they have in place. Uh, but I'm gonna ignore that. Uh, next show storeReply. So we do have some non, um, resourceful actions and that's okay. Um, we might stick with that or we might extract some of these into their own controllers. It just depends again, on how you wanna structure things and what you feel like needs to be done and what is no big deal.
and what you feel like needs to be done and what is no big deal. Um, so for example, instead of a like method here, maybe you have a PostLikesController, and this would be, I don't even know what this does. It creates a, like maybe that would be a store action on that instead, uh, it's whatever you wanna do. Okay, that looks fine. Let me go back to routes. We have functionality for following. Okay, so, so already I'm learning just from this one file
We have functionality for following. Okay, so, so already I'm learning just from this one file that, well we have a homepage, we have some dev specific endpoints for authentication. Uh, we have a way to, uh, view posts. We can create posts, we can repost, we can, uh, like them, we can quote tweet them, we can unlike them, we can follow other users. And then it looks like we also have endpoints to um, show a person's profile.
And then it looks like we also have end points to um, show a person's profile. And there's also one with replies. This is interesting Profile. So you load the following and the followers and that gets appended on. Okay, interesting. And then finally we have one, let's see, ProfileStatus Post. So I would imagine this is if you are on a profile page,
Running and Fixing Tests7:19
profile status post. So I would imagine this is if you are on a profile page, this is an endpoint to show a post within that profile. Okay? Okay, I think I understand what that does. Alright, so the next thing I wanna do is figure out, and I'll save this, the next thing I wanna do is figure out um, are there any tests here? And I really hope there are because if there are, when I make changes, um,
And I really hope there are because if there are, when I make changes, um, I have a little more assurance that I didn't break everything. So let's do that. Now I'm gonna open up the sidebar and take a look at tests. And we have feature and we have just a few and that's fine. A few is enough for a demo course we have Post and it looks like he's using a behavior suffix, that's fine. This is PostBehavior, LinksBehavior, FollowBehavior.
and it looks like he's using a behavior suffix, that's fine. This is post behavior, links behavior, follow behavior. So for posts allows a profile to publish post, fine, it can reply to a post, fine, it can have many, it can create plain repo. Okay? So this is really helpful to me because it teaches me how to use the, the code base. Remember the test don't just ensure that the code works, it's also, uh, education of sorts. If I wanna figure out, well what is involved with uh,
it's also, uh, education of sorts. If I wanna figure out, well what is involved with uh, reposting, I have a perfect example here and that's another way to think of tests. They are examples. Uh, and then we have liking, okay and follows. So I'm gonna cross my fingers in hope that these tests pass. Let's give it a run, uh, test directory unit not found. Let's hide the sidebar.
test directory unit not found. Let's hide the sidebar. And if you ever see this, it's usually because you're missing a folder that is referenced within your configuration file. So if I open UPPUnit.xml, yeah, you'll see it has a test suite configured for unit, but we don't actually have a unit directory here, we're just doing basic feature tests. So if I get rid of that, hopefully if we run this
Automating Formatting and Upgrades9:07
we're just doing basic feature tests. So if I get rid of that, hopefully if we run this again, it'll work in. Good, good job Jeremy. We have, um, a small suite of passing tests. Excellent. Alright, so next up, I'm feeling pretty good here, but I would like to set up, um, a system for automatic code formatting as well as potential upgrades and fixes. So here's what I mean.
as potential upgrades and fixes. So here's what I mean. If I go to PostController, you'll see um, very clearly Jeremy comes from the JavaScript world and he wants his braces on the same line here. Nothing wrong with it at all, but I just want a bit more of a, a common, uh, standard approach in the php world. So in this case, I would want that brace on its own line. And trust me, I'm not gonna manually do this.
So in this case, I would want that brace on its own line. And trust me, I'm not gonna manually do this. We're gonna automatically format it. So as it turns out, if I open up composer.json Laravel includes a tool called pint out of the box. So we can run this on our entire code base like this pint. All right? And you can see it's gone through a bunch of files and it made changes and fixes to 51 files. Okay? Now here's one thing we can also do. If I scroll down, we can set up our own scripts like this.
Okay? Now here's one thing we can also do. If I scroll down, we can set up our own scripts like this. Let's call this, how about format? And yet to start all it's gonna do is defer to pint. Okay? So now with this alone, if I bring back the terminal, I can now say composer run format and that will trigger pint on my entire project. Cool. So now if I were to come back to PostController, yeah, you can see for all of our files, these braces will again follow a fairly standard
yeah, you can see for all of our files, these braces will again follow a fairly standard uh, formatting approach. And in fact, if I were to run git status, you can see all the different files that were updated as part of that. Cool. Alright, next up. Even though we have a brand new project effectively, I still wanna pull in a tool called Rector. Lemme show you if you visit getrector.com. It's basically an automated tool
Lemma show you if you visit getrector.com. It's basically an automated tool that performs an endless series of suites to upgrade your PHP code base. It will add times where they were neglected. It will swap out old PHP syntax with a more modern version. And like I said, even though we have a brand new project, I find that Rector will still pick up on little things that I missed. So I always like to pull this in.
on little things that I missed. So I always like to pull this in. Let's go to docs and we can install it like so bring up the terminal, paste it in. Alright, so now we should have a vendor/bin/rector or rector, uh, command that you can run. And you'll see initially it's gonna offer to create the rector configuration file. Let's do that now. All right,
to create the rector configuration file. Let's do that now. All right, so now we should have a rector.php file in our project root. And yeah, notice it's pretty smart. Did notice which, uh, folder paths to scan by default. Now personally, I'm okay with skipping over that public directory. I might even remove resources in this case and config and just stick with something possibly like this.
I might even remove resources in this case and config and just stick with something possibly like this. But yeah, do whatever you want for your own projects. And then let's do this. Let's defer to with prepared sets. And I'm gonna paste in just a handful here. Now mostly this speaks for itself. Don't worry about this too much. We'll just checking in for dead code. That's code that never gets executed in our code base. Check for quality. Uh, are we using types, uh, check
That's code that never gets executed in our code base. Check for quality. Uh, are we using types, uh, check for early returns, just a handful of things. And of course if you wanna learn more, take a look at the rector documentation. But nonetheless, this now allows me to run rector on my full code base or specifically these paths. Let's do it fender then rector, or again just rector and here we go.
Let's do it fender then rector, or again just rector and here we go. It's getting to work. And let's just have a look real quick at some of the things that it changed. So first it declares strict types at the top of all of our files, generally in 2025. I think this is a good practice to get into next, it adds, uh, uh, types and return types where needed. And again, notice if at any point you don't like something that it's doing, that doesn't mean it's a bad tool,
And again, notice if at any point you don't like something that it's doing, that doesn't mean it's a bad tool, it just means you are free to disable that particular check. So for example, right here in my test file, um, I might be okay with skipping over that void return type for the anonymous function. So at any point you can read the applied rules. So in this case, uh, uh, add closure, void return type where no return rector, uh, that's the one that's being applied here.
where no return rector, uh, that's the one that's being applied here. So what you could do in these cases is if you wanted to disable that entirely across your code base, just copy this switch back and you'll find there is a withSkip method we can defer to anyway, we could just paste this in and you'll see it's a full class path that you could reach for. Okay, so now it's gonna skip over that particular rule.
path that you could reach for. Okay, so now it's gonna skip over that particular rule. And yeah, what I would recommend is doing test runs with rector and then spot anything that you really don't like and you don't want it to apply. And you can either disable that or skip over it, uh, and, and configure it precisely to your needs. Okay, anyways, if I come back one more time, let's see what else is being added here. Yep, we have some void return types.
what else is being added here. Yep, we have some void return types. Yeah, so mostly uh, this is looking pretty good. Uh, it's mostly just adding the return types in the case of the, the void returns on the, uh, the closures here. Again, I'm personally not a fan of that, so this is something that I would disable. Anyways, let's close that out. And now if I come back to composer.json. Alright, so now
And now if I come back to composer, Jason. Alright, so now whenever I run composer run format, I will start by triggering Rector on my code base and then pint. Okay, so now I have a single command to automatically format and update my code base, which is really cool. I think. Uh, also if you wanna set up test versions where you can see the output that these would trigger without physically updating the files, you can do that as well.
that these would trigger without physically updating the files, you can do that as well. Uh, just check the documentation On that note though, let's do a get restore, uh, because you'll remember we decided that the void return types on those anonymous closures with our tests, uh, within our tests, you may like it. I'm not the biggest fan, so I'm gonna delete that entirely. And now because we updated our rector file, uh, right down here, it's not gonna do that when I run it.
And now because we updated our rector file, uh, right down here, it's not gonna do that when I run it. So if I were to start this over from scratch, yep, let's do git status. And now we can see some changes here, but they will not include the return types. So if I were to say git diff on test Feature, how about like Behavior? Let's go to full screen. Uh, yeah, now you can see no return types are being
Let's go to full screen. Uh, yeah, now you can see no return types are being added there, which is good. So let's clear this out. I'm gonna add all of our changes to the staging area. I will commit with set up auto formatting script, something like that. And yeah, with that I am fully comfortable and I hope you are in the next video. We're gonna start writing some code.
and I hope you are in the next video. We're gonna start writing some code.
