Identifying Core Resources0:00
So now that we've got a generic Laravel app up and running, let's talk about what makes this specific app that we're building unique compared to other apps. The first place you want to start are the nouns or the resources that are actually going to be the foundation of everything else we build. So let's get started on those. Let's talk about what our nouns or resources are in Symposium. So because it's a software as a service, we're going to have a User because Users have to be able to log in. So we're going to assume that's there by default, and Laravel actually gives us a User model by default. Second thing is, it's all about managing Talks, right? Symposium is an app for conference speakers to use to manage their Talks. So we're going to have Talks for sure. And then finally, there are Talks at conferences. And part of Symposium is figuring out which conferences do you want to submit to, which conferences have you submitted to. So we need an entity in the system to represent this concept of Conferences. We can always change the names and the attributes of our entities later, but it's still very helpful for us to understand basically what they're about at the very beginning of the project. So one of the things I like to do there is I like to create as many of the useful files as possible with an understanding of what it's going to generally look like at the very beginning. Because there's these really helpful tools that when you're creating a model in Laravel, you can also pass along flags saying I also want to create other things along with it.
Generating Models and Files1:07
So one of the things I like to do there is I like to create as many of the useful files as possible with an understanding of what it's going to generally look like at the very beginning. Because there's these really helpful tools that when you're creating a model in Laravel, you can also pass along flags saying I also want to create other things along with it. So if you go to php artisan help, you can pass in any command to this and it'll give you the definition about what other flags or configuration items you can pass. So if we want to say make:model, this is going to tell us what things we can pass in to make a model. So we've got the controller, you know, to make an empty controller for it. Or if you pass -r, it'll generate a resource controller. If you pass -f, you're going to get a factory for the model, -m a migration. You can even hit -a and get all of these things, and we don't actually want all of them. I want a migration to create it in the database for sure. I want a factory to make it easy to generate a new one.
I want a migration to create it in the database for sure. I want a factory to make it easy to generate a new one. I want a resource controller to make it easier when we're getting started with the CRUD, even though that's next video. And I want to make those things with a general assumption of what they should be shaped like that reflects Laravel's default thinking of where they should be. So we run php artisan make:model, pass in the name of our model, and then we pass in our flags. So migration, a factory, and a resource controller. Now let's do the same thing for a conference. And so now we have those basic files running for both of those really important nouns or resources or entities that we have. So let's get started by taking a look at those files. So if we open up our directory instruction, we can see where they live.
Reviewing Created Structure2:40
So let's get started by taking a look at those files. So if we open up our directory structure, we can see where they live. Our controllers, which we're not going to use right now, live here, and they are resource controllers. So they've got all the basic methods for listing the resource, creating and storing, showing, and then editing and updating, and then finally deleting or destroying that resource. We've also got the individual model for each of them, which doesn't do anything other than exist and have a factory. And then we've got our database factories and our database migrations. The migration is where we define what it looks like to create a table. The factory is what it looks like for us to say if you need to create a new instance of this, we're going to give you fake data so you don't have to pass in all the fake data every time. It makes it super easy to spin one of these up for a test or for the initial seeds. So let's get started by defining what actually is in a talk.
Defining Talk Schema3:27
It makes it super easy to spin one of these up for a test or for the initial seeds. So let's get started by defining what actually is in a Talk. So a Talk has a title. It's got a length. And I'm going to use a string here, mainly because I want people to be able to type things like 45-60, like it's a 45 to 60 minute thing, rather than an integer, which would require them to pick a number. We've got a type, which is going to be out of a list, but we don't use database enums. We're just going to keep it as a string. We've got, let's see, we've got the abstract, which is longer, so it's going to be text. And we've got the organizer_notes, which is longer, so it's going to be text. So at this point, we've got a pretty decent basic migration for our Talk, so let's jump over to the other files.
And we've got the organizer notes, which is longer, so it's going to be text. So at this point, we've got a pretty decent basic migration for our talk, so let's jump over to the other files. I like to keep my models as simple as possible, but one of the things I definitely like to do is to use guarded to avoid the mass assignment issues, and I don't have time for that in this particular series. But just know that if you try to assign properties to a model all at once using arrays, if they are not marked as explicitly fillable, Laravel won't let you do it. And it's a security protection, but if you work like I do, you don't need that security protection. So I'm not saying you should necessarily do this, but I do recommend learning enough to get to the point where you can just do it this way. But now that I'm in this model, it actually makes me think, I want to be able to say who is the person who authored this talk. You know, something like a public function author.
But now that I'm in this model, it actually makes me think, I want to be able to say who is the person who authored this talk. You know, something like a public function author. But that would require us to have a thing in the migration, in the database table, that attaches a talk to a User, which we didn't set up in the first place. Quick note, I knew that. I'm doing this on purpose because I want to point out the fact that migrations don't have to be precious until they've been pushed up to your version control where other users in your project can get access to it and it's probably deployed to a server. As long as it's on your local, you can have migrated or not migrated and make changes to your migrations. Because we're not being precious about the state of our local database,
As long as it's on your local, you can have migrated or not migrated and make changes to your migrations. Because we're not being precious about the state of our local database, we're not worried about the fact that we might have to make some changes and then rerun php artisan migrate:fresh, then we can just make these changes to our database tables, make these changes to the migrations, make these changes to the seeders, and just rerun php artisan migrate:fresh without stressing out about it. It is very important to not be precious about your relationship to the data that is in your local database. So let's go back real quick. We are going to relate this to a User.
Relating Talks to Users5:57
So let's go back real quick. We are going to relate this to a User. So now we can rely on having that in our model. Say this belongs to User. And now we can go to our User model and say a User has Talks. And now they're related. All right, so now let's build out the factory. So we go to our TalkFactory. This is where we define if someone were to just pull a Talk out of thin air, what does it look like for that Talk to actually have some fake data in there that we can work with,
Building Talk Factory6:36
This is where we define if someone were to just pull a talk out of thin air, what does it look like for that talk to actually have some fake data in there that we can work with, especially in tests and seeders. So we basically want an entry in this array for every single property. So we start with the title. Actually, let's start with the User. So what you want to do is give the class of thing you're creating this. So it's a User. And then you just say factory. And we're not actually going to say create.
And then you just say factory. And we're not actually going to say create. We're just passing it the actual factory for the User. The benefit of that is we're not creating a new User every single time this method runs, because what if in generating this factory they pass in a userID? Well, then this User would be created and then thrown away. So by passing in this factory, it only actually calls create on this when it sees that a userID hasn't been passed in. Laravel is smart enough to do that for us. So it saves us from extra Users being created if they're not actually needed.
Laravel is smart enough to do that for us. So it saves us from extra Users being created if they're not actually needed. All right, so we've got our title, Faker. If you're not familiar, Faker is a library that makes fake content, structured fake content for us. So we've got our length. And for now, I'm not going to worry about the whole, you know, 45-60. We're just going to say a random number somewhere between 15 and 60 minutes. Let's see, our abstract is going to be a paragraph. Our organizer notes are going to be a paragraph.
Let's see, our abstract is going to be a paragraph. Our organizer notes are going to be a paragraph. Oh, and our type. So our type's interesting because it is going to be pulled off of a list, and a list of possible states. So if you are a php developer, you say enum. Remember I said we don't use database enums. But I didn't say we don't use PHP enums. We love PHP enums. So let's create a new enum.
Creating Talk Type Enum8:27
We love php enums. So let's create a new enum. And we'll use it to store the possible talkType. We'll just say talkType. Okay, so we've got a talkType enum that returns a string. And because we're making this enum backed by a string, for each of our cases, we can then just say case lightning. It's going to have an actual string attached to it, lightning. And it's going to be a standard talk. And then we've got a keynote.
And it's going to be a standard talk. And then we've got a keynote. So this enum can be used in lots of different places. We can use it in our validation. We can use it in our factory. There's lots of places we're going to use it. And doing it in code is so much more powerful and flexible for the future than doing it in the database. So now we can just say, I want one of those. You can say fake.
So now we can just say, I want one of those. You can say fake. random element. Yep, so they're basically saying, give me a random element out of this array. And we'll see if I remember correctly. I believe the best way to do it is talkTypeCases. And then that's going to give you not an actual string, but it's going to give you the enum response. And then you say you want the value of it.
Seeding Talks and Testing9:51
but it's going to give you the enum response. And then you say you want the value of it. So now we've got all of our properties on the Talk with a definition of how to create them randomly without any input passed in from the user. All right, so we've got the migration, the factory, and now it is time to throw this into the seeder. Now you could create a seeder for every single entity. That's a perfectly reasonable way to do it. Personally, I like throwing a story,
That's a perfectly reasonable way to do it. Personally, I like throwing a story, basically, in the database/seeder. So I'm just going to say, what are the things that are most important for me to really have the app up and running? I'm going to be able to see it all together in one here. So I usually create a User. Look, we've got our test User here. And then for this User,
Look, we've got our test User here. And then for this User, we want to be able to say this User has specific things. So we can say hasTalkFactory()->count(5). And then we put our create() in here. So now we're basically saying, when we create this User, make sure this User has exactly five talks. So this will be great,
make sure this user has exactly five talks. So this will be great, because this will set this up for us, but it'll also prove that our TalkFactory was actually set up correctly, because sometimes I make typos. So this is what I was telling you about earlier, where we want to be at a place where at any given moment we can write php artisan migrate:fresh
where at any given moment we can write php artisan migrate:fresh and not worry about what it's doing to our database. So we want to do php artisan migrate:fresh --seed, and then it's going to run the cedars for us at the same time. Let's actually take a look at our database, though. Now, offscreen, I set up our TablePlus connection.
Now, offscreen, I set up our TablePlus connection. Remember, we did in a previous video, we set up a connection to the remote. But you can also set up a TablePlus connection to type SQLite. And all it asks you to do is pick the file. So I made a TablePlus connection called SymposiumLayerCastsLocal, and I open up the file.
called SymposiumLayerCastsLocal, and I open up the file at database/database.sqlite. And so if we go over to TablePlus, we see that there's a few SQLite-specific tables in there, but everything else is just where you're used to in a normal Laravel app. And then we've got Talks, and we've got Conferences. So if we
Talks, and we've got Conferences. So if we come over to Talks, we can come in here and see that for userId 1, we've got a whole bunch of talks with different random types and different lengths between the numbers of 15 and 60. The funny thing, I used a title.
15 and 60. The funny thing, I used a title. I meant to do a title, but it was actually, this is the title of a person, so we probably should just use Sentence for that one. So we'll go over to our TalkFactory, and we'll go for Sentence instead. Because we are so comfortable with
instead. Because we are so comfortable with php artisan migrate:fresh --seed. I actually have a shortcut for that, which is MFS. Remember, we just want to run this all the dang time and just get comfortable with it. And now we see titles that seem a little bit more like what a talk title might look like.
Defining Conference Schema12:48
seem a little bit more like what a talk title might look like. So now that we've got all this working, let's do the same for conferences, but a little bit faster since it's not all fresh this time. We've already created it, so we want to go to our Conference table migration. So what does a conference have? It's got a title, it's got
So what does a conference have? It's got a title, it's got a description, let's give it a URL, we should give it a location, and a bunch of dates. So we've got a couple different options. We've got Date and DateTime. We only care about the date for this one, for all of these actually, because they're about a day.
We only care about the date for this one, for all of these actually, because they're about a day when it starts, or a day when it ends. Not necessarily a specific date time. So we're going to create a StartSet and EndSet, and then we're also going to do the CallForProposal or CFP Start and End.
we're also going to do the CallForProposal or CFP Start and End Dates, because some of the functions that we want to have in Symposium will be defined based on which conferences that you're interested in even have a CallForProposal open right now, and that CFP Start and End Date are different than the Conference Start and End Date, because they have to close the CallForProposal
than the Conference Start and End Date, because they have to close the CallForProposal weeks to months before the conference starts, so we need to track those separately. And unlike talks, conferences aren't attached to a User, so we don't need to worry about that foreign ID that we created for the Talk. So let's go to our Conference model and unguard it. Let's build up the factory.
Building Conference Factory Dates14:14
and unguard it. Let's build up the factory. Alright, so what are the fields that we just added? We've got Title, let's FakeSentence, Location, we can do FakeCity, Description,
City, Description, Oh, URL. And then we get to the most complicated part, which is the dates. And this is because dates very often need to have a specific relationship with each other. You can't just have a whole bunch of random dates in the same way that an app that's
You can't just have a whole bunch of random dates in the same way that an app that's finance related can't have a whole bunch of random numbers that don't necessarily have the appropriate relationship to each other. And so this is when your factories get a little bit more complicated. There's a few different ways to do it, but my preferred way to do it is just to write above the definition in the same function here. We're just going to
the definition in the same function here. We're just going to create some variables that allow us to refer to them and refer to each other down here. So I'm thinking everything is really going to start around this startsAtDate. And so we're going to take now, and we're just going to say let's make it six months in the future. So we've got that
let's make it six months in the future. So we've got that startsAtDate, that's going to be when it starts and we can just use that. It should end let's call it three days afterwards. So we can say endsAt equals startsAt clone days 3. Okay, great. So what about the CFP? Well, I think
days three. Okay, great. So what about the CFP? Well, I think it should start. We could do it super random if we wanted, but I'm just, I don't know if I care. So we're just going to say CFP startsAt the startsAtDate and we're going to sub months 4. And then the CFP can end at
four. And then the CFP can end at CFP startsAtDate and let's say it's a two month CFP or something like that. Great. So we've got this startDate six months from now. We've got an endDate that is three days after that. We have a CFP startDate that is four months
after that. We have a CFP startDate that is four months prior to that, which is two months from now. And the CFP endDate that is two months after that, which is four months from now. You can make these more variable. You know, you can say, you know, subtract between one and four, but we've got to be careful with is that it's not to a state where if the one random
got to be careful with is that it's not to a state where if the one random is the lower and the next random is higher that they conflict, or if one random is higher and the next one is lower, they conflict. So you really want to make sure that your factories end up in reasonable states for important dates or numbers or calculations or whatever else. So now that we have these, we realize that these are all
or calculations or whatever else. So now that we have these, we realize that these are all short enough that if you really wanted to, you can put them in line. If you put them in line, you wouldn't be able to refer to their variables quite as easily. So I'm perfectly fine to just have the logic for the dates in here, especially because it gives us space to make the date logic more complicated in the future, and just throw them all in here. So startSat,
logic more complicated in the future, and just throw them all in here. So startSat, endSat. So let's now go add a few conferences to the cedar, and the conferences don't have an owner, so they don't need to be set up there. We can just say conference::factory()->count()->create(); And that's it. So let's
count create. And that's it. So let's go run it and see how it works. First thing I like seeing is no errors. You know, nothing broke. So let's go take a look at the database. And we'll take a look at conferences. And alright, so we got our title,
at conferences. And alright, so we got our title, we have our location, and obviously you don't have to do it exactly like this. You might want it to be, you know, including the state or whatever. Description, URL, and our dates. And you'll notice that we used date, not datetime in our column types, but because
SQLite Date Storage Notes18:03
in our column types, but because this is SQLite, SQLite doesn't actually have a date column, so these are just strings basically rendered from Carbon. And this is one of the downsides of working with SQLite locally, is this is not what your data would look like if you're using MySQL or Postgres. So that is one reason
MySQL or Postgres. So that is one reason to choose as a more experienced programmer to choose to use MySQL locally, so it's more similar to what your production database is going to look like, unless your production database is SQLite. Alright, so we built out database migrations, models, factories, seeders, and actually
Wrap-Up and Next Steps18:35
migrations, models, factories, seeders, and actually controllers which we'll use later for our primary entity types that we're going to be dealing with. So that's enough to get a lot working, but in the next one we're actually going to allow the User to interact with them. We're going to build out the CRUD pages and the controllers and the views and the validation and everything else, so I'll see
CRUD pages and the controllers and the views and the validation and everything else, so I'll see you next time.
