In this article, we are going to finish up the last two topics in Laravel, database relations and controllers, and before we can start building our blog application, let’s first use what we’ve learned so far to create a simple homepage.
Let’s start with database relations. In a typical application, the database tables aren’t always independent. For example, we could have a user who has posts, and posts that belong to a user. And Laravel offers us a way to define these relations using the Eloquent models.
This section is probably a little difficult for beginners, but don’t worry, we are going to come back to this topic when we start building our blog app. Here, I only picked the ones we need to use to build a simple blogging system.
This is the most basic relation. For example, each User
is associated with one Phone
. To define this relationship, we need to place a phone
method on the User
model.
|
|
This Phone
model automatically assumes that there is a user_id
column inside the phones table. This means you also need to define this column in the migration file. The user_id
column stores the id
of the user that owns this phone.
Now, what if we want to do the opposite? The inverse of “has one” would be “belongs to one”. For example, each Phone
would belong to one User
. In order to define the inverse of the one-to-one relationship. We place a user
method on the Phone
model.
|
|
A one-to-many relationship is used to define relationships where a single model owns any amount of other models. For example, one Category
could have many Post
s. Just like one-to-one relation, it can be defined by putting a posts
method in the Category
model.
|
|
Here the Post
model assumes the posts
table has a category_id
column.
However, sometimes we need to find the category through the post. The inverse of “has many” would be “belongs to”. In order to define the inverse of the one-to-many relationship. We place a category
method on the Post
model.
|
|
The many-to-many relation is a little more tricky. For example, we can have a User
who has many roles, and a Role
which has many users.
|
|
|
|
These two models assume there is a role_user
table in the database. And the role_user
table contains user_id
and role_id
columns. This way, we can match the user with the role and vice versa.
Now that we’ve studied routes, views, models as well as database relations, it’s time to talk about the thing that connects them all together. Remember when we talked about routes, we saw an example like this?
|
|
It looks fine right now, but when you have a huge project, putting all the logic in the route file will make it very messy. A better solution would be making sure that the route always points to a method in a controller, and we’ll put the logic inside that method.
|
|
To create a new controller, use the following command:
|
|
Laravel’s controller files are stored under the directory app/Http/Controllers/
.
Let’s take a look at an example. The show()
method expects a variable $id
, and it uses that id
to locate the user in the database and returns that user to the view.
|
|
Sometimes, you need to define a controller that only has one method. In this case, we can simplify the code by changing the method’s name to __invoke
:
|
|
|
|
Now we don’t have to specify the method name in the route.
The resource is another modern web design concept we need to talk about. Usually, we see all the Eloquent models as resources, meaning that we perform the same set of actions on all of them, create, read, update and delete (CRUD).
To create a resource controller, we can use the --resource
option:
|
|
The generated controller will automatically contain the following methods:
|
|
The comments explain their corresponding function and purposes.
Laravel also offers us a very easy way to register routes for all of these methods.
|
|
The following routes with different HTTP methods will be automatically created.
HTTP Method | URI | Action | Route Name |
---|---|---|---|
GET | /photos |
index | photos.index |
GET | /photos/create |
create | photos.create |
POST | /photos |
store | photos.store |
GET | /photos/{photo} |
show | photos.show |
GET | /photos/{photo}/edit |
edit | photos.edit |
PUT/PATCH | /photos/{photo} |
update | photos.update |
DELETE | /photos/{photo} |
destroy | photos.destroy |
Now, we are finally going to start using everything we’ve learned about Laravel so far, and use it to create a real project. Let’s start with something easier. In this part, we are going to create a sample homepage, which only contains three variables, a name, a description and a logo. But through this example, I’m going to show you exactly how to retrieve these data from the database, how to create new data, and how to save them in a real web application.
If you’ve followed the previous tutorial, you should already know how to create a Laravel project. As a quick reminder, this is what we need to do:
|
|
Remember to configure the .env
file and database like we’ve talked about before.
Next, let’s start with the database. We’ll create a migration file for the home
table. This table should contain the website’s name, description and logo. In the case of the logo, the database can’t really store files, so instead, it stores the path which points to the location where the file is stored.
Generate a migration file:
|
|
|
|
In this example, we created six columns in the home
table. id()
creates an ID column, which is commonly used for indexing. timestamps()
creates two columns, created_at
and uptated_at
. These two columns will be automatically updated when the record is created and updated. And finally, string()
creates a column with type VARCHAR
, whose default length is 255 bytes.
To apply the changes, use the following command:
|
|
To view the changes you’ve made, you can use software such as DB Browser for SQLite or PhpMyAdmin, depending on what database you are using.
Now, we can create the corresponding model file for this table.
|
|
By default, this generated model expects a table called homes
, which doesn’t make sense here. So we need to tell Laravel that we are using the home
table. And we want to be able to mass assign columns such as name, description and logo, so we need to create a $fillable
property.
|
|
For now, we need only three pages to make this sample homepage work. We need a create
page to create the required data, a success
page that tells you the required data has been successfully created, and finally, a home
page that displays the data. And don’t forget the layout
.
layout.blade.php
|
|
create.blade.php
|
|
There are two things we need to notice when we use forms to transfer data in Laravel. The first one is csrf_field()
. CSRF is a malicious attack targeting web applications, and this csrf_field()
function provides protection against that type of attack. You can read more about CSRF (Cross-site request forgery) here.
The second thing we need to pay special attention to is the name
attribute in every <input>
or <textarea>
element. When the form is submitted, the user input will be tied to a variable, whose name is specified by the name
attribute. For instance, when name="description"
, the user input will be tied to the variable description, and we can access its value using $request->input('description')
. We’ll see how this works later.
success.blade.php
|
|
home.blade.php
|
|
Now we have the database and the views ready, we can start writing the logic for our homepage. Let’s create a HomeController.
|
|
This controller contains seven different methods and each of them has a different function. In this article, I’m going to walk you through index()
, create()
and store()
. As for the rest, even though they have different purposes, they do share the same logic.
Next, we create routes for these methods.
|
|
This line of code will create a route for each method in HomeController
, we can list all of them like this:
|
|
Create and Store
Let’s start with create()
.
|
|
This is an easy one, we hardcoded and passed one variable name
to the view, because the navbar requires the variable, but it is not in the database yet. We can test it by visiting http://127.0.0.1:8000/home/create
Now we can fill in the data, and when we click the Submit button, the browser will go to /home
with a POST method, which triggers the store()
method.
The store()
method is a little bit tricky to deal with. First, there are two things we need to import, the Home
model, since we need to access the database, and Storage
, since we need to upload a file.
|
|
The text-based data is relatively easy to deal with. We use the input()
method to retrieve the data from the request. Remember that the argument for input()
must match the name
attribute. And then, we can create a new Home
record, and put the data in the corresponding column.
When dealing with images, we first use file('logo')
to get the image file, and store('logos', 'public')
sends the image to the logos
folder in the public
disk. In Laravel, there are a few disks defined, and the configuration file is located at config/filesystems.php
. Each disk points to a different location in the Laravel file system.
|
|
In our case, we are using the public
disk and it points to the /my-app/storage/app/public
directory. And as we specified in the store()
method, Laravel will create a logos
folder and put our uploaded image inside.
Notice that Laravel automatically changes the name of the image file to avoid any conflicts. And finally, store()
will return a path, which points to the location of this image file. This is what is stored in the database.
Index
Now that we have the required data in the database, we can try to display that data. Since we only have one record in the database, using the index()
method makes more sense than show()
.
|
|
Storage::url($home->logo)
will generate the URL that points to the image file. This only works if you’ve created the symbolic link using the following command.
|
|
This creates a link from public/storage
to storage/app/public
. The URL points to the public
folder, and it can only access this folder through this symbolic link.