Laravel 5.8 From Scratch: Config, ENV, Migrations, and Todos CRUD

Sagar Maheshwary
10 min readApr 5, 2019

--

In the previous tuturial, We talked about laravel framework, How to install it, An introduction to MVC architecture, Created routes, controllers. and views. In this tutorial, we will talk about Models, Database Migrations and make CRUD (CRUD means Create, Read, Update, and Delete from a database) operations on todos table with MySQL.

.ENV File

Before creating migrations, We will need to setup our database, assuming you know how to create a database using phpmyadmin. After creating the database, we will add the database credentials in our application. Laravel has a .env environment file which will have all the sensitive data like database credentials, mail driver credentials, etc because it’s not recommended to store such information directly inside the code (environment files are not limited to PHP. They are used in all other major frameworks). Values inside the .env files are loaded inside the files from the config directory. .env file is located at the root of our application. Let’s take a look at the file (Below is not the complete env file. I have just paste the variables that are important for beginners to know):

All APP values are loaded in config/app.php config file and DB values in config/database.php.

Note: Whenever you making changes to .env file then don’t forget to restart the server ( if you are using laravel dev server) and if you are using a virtual host and changes don’t seem to take effect then just run php artisan config:clear (This command will clear the configuration cache) in your terminal.

Migrations

Since we have setup our database, now let’s take a look at database migrations. Migration are used to store the details about a database table and it’s properties so you don’t have to manually create all the tables by going to the database interface or something like phpmyadmin. We can create migrations using artisan with “make:migration” command:

php artisan make:migration create_todos_table

In laravel, the name of the model has to be singular and the name of the migration should be plural so it can automatically find the table name. You can find these migration files in database/migrations directory. Laravel by default comes with two migrations namely users and password_resets (all migration files are prepended with a timestamp), which are used for authentication. If you want to create a migration but have a different table name in mind then you can explicitly define the table name with “ — create” flag:

php artisan make:migration create_todos_table --create=todos

When you open the create_todos_table.php. You will see two methods, up() and down(). up() is used for creating/updating tables, columns, and indexes. The down() method is used for reversing the operation done by up() method.

Inside up() method, We have Schema:create(‘table_name’,callback) method which will be used for creating a new table. Inside the callback, we have $table->bigIncrements(‘id’) which will create an auto_increment integer column with a primary key and argument ‘id’ is the name of the column. Second one is $table->timestamps() which will create two timestamp columns created_at and updated_at. created_at will be filled when a row is created and updated_at when a row is updated. We will add two columns title and body (for the sake of simplicity) but if you want to know the available columns types then see the list.

You can also specify length to a string column as the second argument:

Before running any migration commands we need to add a line of code inside the AppServiceProvider.php which can be found in app/Providers directory. Open the file and inside the boot() method, add this line:

Above code will set the default length of a string column to 191. Since laravel comes with utf8mb4 charset as default which supports emojis and it’s max length for a unique key is 191. If it exceeds the limit then laravel will generate an error and won’t run migrations. If you want to specify a different charset then you can set it in database.php config file.

To run migrations, We can use “migrate” command:

php artisan migrate

Above command will run the migrations and create all the tables. It will execute the up() method. If you want to reverse the migrations, you can use migrate:rollback command which will execute down() method:

php artisan migrate:rollback

Models

After creating the tables, We will create model that will interact with the database resource (table) e.g Post model for posts table. To create a model we simply need to run make:model command:

php artisan make:model Todo

We can also add -m flag which will create a Model as well as a migration for it.

php artisan make:model Todo -m

Above command will also create a migrating named create_todos_table. You can find all the Models inside the app directory. Let’s open the Todo model.

We can specify properties to modify the behavior of a model. Let’s start with $table property which is used to specify the name of the table that this model will interact with. By default, It will define the table name as the plural of the model name e.g todos table for Todo model and users table for User model. When you don’t want to use timestamps on your table then you will also have to specify $timestamps property and set it to false in your Model because Laravel expects your table to have created_at and updated_at timestamp columns.

Above is just an example, so you don’t need to put it in your code to follow this series.

Todos CRUD

Now all the basic stuff is done, let’s start creating views for our todos and add functionality to our TodosController. We will have 4 views Index, Create, Edit, and Show. So let’s create a folder named todos inside the views directory and create all those four views. After that, we will first create the controller:

php artisan make:controller TodosController --resource

Note that we have also added a — resource flag which will define six methods inside the TodosController namely:

  1. Index (used for displaying a list of Todos)
  2. Create (will show a view with form for creating a Todo)
  3. Store (used for creating a Todo inside the database. Note: create method submits to store method)
  4. Show (will display a specified Todo)
  5. Edit (will show a form for editing a Todo. Form will be filled with the existing Todo data)
  6. Update (Used for updating a Todo inside the database. Note: edit submits to update method)
  7. Destroy (used for deleting a specified Todo)

These methods are not specific to TodosController. It can be used for PostsController, CommentsController or any other resource. (A resource is an object e.g user, todo or anything else)

Let’s add the routes to our web.php files:

We can pass dynamic parameters with {} brackets and you might have noticed that show, update, and destroy has the same url but different methods so it’s legit. Just like — resource flag, laravel has a method called resource() that will generate all the above routes. You can also use that method instead of specifying them individually like above:

After defining routes, we need to add the links to our navbar so open the navbar.blade.php view inside the inc folder and update the <ul> that has the links for the right side of our navbar:

Displaying Todos

Now open the TodosController so we can modify our Index method:

We are retrieving all the todos with Todo model and ordering by created_at column in descending order then we are chaining it with paginate() which will create pagination links and by default the items displayed per page is 15. After retrieving todos, We are returning a view with $todos array. We can pass data to a view by passing an array of data as a second parameter to the view() method.

We also have to import the Todo class to our TodosController:

Some helpful methods for retreiving models:

Now, we can add the markup to our Index view inside the todos folder:

Inside the content section, we are using @forelse() loop to iterate todos and content inside the @empty works as an else statement if an array or collection is empty. Blade has @for() , @foreach(), and @while() loops too. Of course, you need to end this @forelse with @endforelse(). Inside @forelse(), We have some HTML markup and you can see that we are echoing $todo object properties. str_limit() is a helper function used to limit the number of string characters and diffForHumans() is used for displaying date in a more readable format e.g 1 day ago or 1 months ago. We are displaying the pagination links with $todos->links(). By default, Laravel supports bootstrap pagination but if you are using a different framework like materialize-css then you can specify custom pagination view inside the links() method. Laravel already comes with some default pagination views. You can publish these pagination views with below command:

php artisan vendor:publish --tag=laravel-pagination

Above command will copy the pagination views to our views/vendor/pagination directory. Then you can specify the view like this:

There will be more than one pagination views. You can customize the view however you like. Now, when you navigate to todos page, you will see “Nothing found!” since there are not todos in the database.(we will create them now)

Creating A Todo

Let’s modify the create method of TodosController which will simply return a view with a form for creating a todo:

Adding the markup to create view inside the todos folder:

We have a form with POST method submitting to a name route “todos.store”. Inside the form, we have @csrf will generate a hidden input named csrf_token which is important for security and without that you will not be able to submit a form (You will see a page with “Page expired” text after form submission or a 419 error page). old(‘field_name’) is a helper function used for echoing the old values from a submitted form e.g if you failed the validation and got redirected back to the form then you will need those values that were previously filled. Validation errors can be accessed by $errors object. To check for validation failure, We can use $errors->has(‘field_name’) and $errors->first(‘field_name’) will echo the first validation error.

“field_name” is the value of the “name” attribute defined in our input fields. In our form, we have “title” and “body” fields.

Let’s modify the Store method of our TodosController which will store the todo to the database:

Store method has $request object as a parameter which will be used to access form data. First thing you want to do is validate the form data. We can use the $request->validate() method for validation, which will receive an array of validation rules. Validation rules is an associative array. Key will be the field_name and value with be the validation rules. Second parameter is an optional array for custom validation messages. Rules are separated with pipe sign “|”. We are using the most basic validation rules. First is “required” which means the field_name should not be empty (“nullable” rule is vice versa), “string” means it should be a string value, “min” is the limit of minimum characters for a string in an input field and “max” is the maximum characters. “unique:table,column” with see if the same value does not exists in the database (comes handy for storing emails or any other unique data). If validation fails then it will redirect us back. After validation, we are create a new object of the Todo model. Since Todo and Request are both objects, We can access their properties with arrow “->” operator. After specifying the values to the model properties, We can call the save() method which will save the Todo to the database. When a Todo is successfully created then we are redirecting the user to a specific route and chaining it with with() method which will make the data available for the next request so we can use it as a flash message. Since this will be stored in session, We can access the value with session(‘status’) as well as check if the a value exists.

Some Methods for accessing form values that are useful:

Helpful redirecting methods:

We also need to display the message as bootstrap alert so open the app.blade.php layout file (so we can make this alert available in every view) and add the below code right after the app.js script:

Let’s add a little css in the <head> tag for our alert:

Displaying a Single Todo

Let’s open the show.blade.php and add the following markup:

All that’s different in our view is that this time we have a single Todo and since it’s a single object we don’t need a loop. There’s an Update button that with open the edit todo view and there’s also a Delete button that will open the modal for confirmation and when you will click the Proceed button it will submit a hidden form having an id of “delete-form” (we will work on destroy method after show method). We are making a delete request when deleting a specific resource so simple anchor tag will not work and a form is needed. Since HTML forms only support GET and POST methods, We will need to add @method(‘DELETE’) which will generate an input field with a value of DELETE ( PUT for updating a resource). Let’s modify the show method in TodosController.

To get a specific resource with an id column, We can use findOrFail() method this method will throw a 404 error if it fails to find the resource. If you want to find a resource by a different column then you can use where(‘column’,’value’) and chain it to firstOrFail() method. For example:

Delete a Todo

We have already created a button in the show view that submits to this method. Now we can modify the destroy method that is responsible for deleting the Todo and all we need to do in this method is fetch the specified Todo and call delete() method on it.

Updating the Todo

Edit method is same as show method just views are different because we will display the values of our todo object in an html form:

Let’s add the markup for our last view edit.blade.php:

This view is the same as the create.blade.php, the difference is that it’s submitting to update method of TodosController having a @method(‘PUT’) inside the form. We are also echoing the values from the $post in the input field with a ternary operator and if validation fails then we will have old() value instead of $post values. Lastly the update method of our TodosController which is same as store but we are updating an existing resource:

There is a scenario when you want to update the todo body but not title then you will get a validation error saying the title should be unique. In these cases we can specify the id of that model to ignore.

Now we can create, display all todos, display a single todo, update them, and lastly delete them, Next tutorial will be on authentication and middleware.

Feel free to comment below or create an issue in the github repo. Here’s the link to the next tutorial:

Source code for this tutorial series:

--

--