Laravel 5.2: Getting started

Please note. Like everything on this website. These posts are merely to allow me to document my journey through various tasks. It will not cover everything, nor be well written. There are definitely better resources out there, please consider using them instead!

Also: This specific post will very much follow the Intermediate Task List on the Laravel site. I have not had an original thought since 1980.

Getting Ready

In order to play, make sure that you have completed the following:

  1. Installed Laravel, created a project and performed the required permission edits.
  2. Create a database, a database user, and edit the .env  file to allow Laravel access.
  3. Tell your significant other that you love them. ūüôā

Prepping the database

Laravel’s Artisan and Migration tool is like version control for your database. It allows you to define a structure for your database so that everyone can start on the same page.

This little project will be dealing with user accounts and authentication, and a todo list, our database will need a users and a tasks  table.

A basic structure for the users¬† table has been automatically created by Laravel, so we don’t need to manually create it.

Use the following command to create the framework for the tasks  table:

A need migration file for the tasks table has now been added to the  database/migrations folder of your project. The migration tool has already added code to create an incrementing ID column, as well as code to create timestamp columns for us. Our tasks table will need to have a column holding the user_id of who created the task, and a column to hold the name of the task itself.

Edit the file with the name ending in  create_task_table.php so it looks like the example below:

Now to run the migration, which creates the actual table(s) in the database, with the following command:

Use your database client to have a look at the newly created tables.

Models (Eloquent part I)

Eloquent is a tool that will help us to work with the database via our “models.”

The user¬† model has already been created by Laravel. It can be found at¬† app/User.php¬†. Nothing else to see here…move along.

The task  model will now be created by us, using the following command:

An empty app/Task model file will have been created for you.

Since every table is guarded against mass-assignment, so we have to specifically state that the  name attribute is mass-assignable. This is done by added the table name to the special $fillable array;

Relationships (Eloquent part II)

Now our required models are defined, we need to tell Laravel how the user  and task tables relate to one another. One user can have many tasks, but a task can only belong to a single user (no sharing yet!). So we set this one-to-many relationship in the models.

First, edit the User  model to add its relationship to the tasks  model:

Now edit the Task  model to state how it relates to the User  model:

Now our relationships have been defined!

Routing

Routes in Laravel are defined in  app/Http/routes.php . Here we will be introducing controllers and using them to handle most of our routes.

Our  / route is currently already defined to return a view template, which we will be defining later.

Authentication

Laravel has already created a special controller at  app/Http/Controllers/Auth/AuthController.php .  This controller uses a special AuthenticatesAndRegistersUsers  trait which will be use in creating and authenticating users.

We still need to created the required views and define route that will point to the correct controller. We can do this by using the following command:

The command has created a bunch of new views for us. Now we need to create the routes for our authentication needs. Luckily, this is very simple. Edit your app/Http/routes.php  by adding the following line within the  ['middleware' => ['web']]route group:

The Task Controller

We will be retrieving and storing tasks, so we will be using a Task Controller. Let’s use the Artisan tool to create a new controller for us. Use this command to create a new controller in the¬† app/Htpp/Controllers¬† directory:

Now create some stubs in the app/Http/routes.php  file to point to the new contoller. Remember to put these in the ['middleware' => ['web']] route group also:

Authenticating All Tasks Routes

We want all task routes to only be available to users who have logged in (authenticated). Laravel uses the middleware¬†method to make this simple. ¬†Let’s add the auth¬† middleware to the controller’s constructor so that all TaskController actions will require the use of this middleware.

Layouts and Views

The first thing we are going to do here is to create a basic layout that will hold the common features which appear on most pages. The is done by creating a layout view that uses the Blade template engine.

Create a new layout view in  resources/views/layouts/app.blade.php  with the following content:

The only line that is not HTML,  @yield('content') , is a special blade directive. It specifies the location for displaying the contents of any child page that extends this layout.

Child View

Now we are going to define out view that will have the form for adding tasks and a table listing all tasks already in the system. The Bootstrap CSS stuff, used to make it all pretty, is included but has been labeled as such. It’s not laravel and you can ignore it if you want.

The first line, @extends('layouts.app')  shows that this view is extending the layout we defined earlier at  resources/views/layouts/app.blade.php . So anything between @section('content')  and @endsection   will be displayed at the @yield('content') directive in the app.blade.php  layout.

The @include(‘common.errors’) directive, at line 14 above, will load a template located at¬† resources/views/common/errors.blade.php¬† (which we will define later). Not surprisingly, this file will handle the retrieving and displaying of error messages.

Now we have a basic layout and view, let’s add an index¬†method, which will return this view, to our TaskController¬†.

Adding Tasks

Now we will add code the store  method to our TaskController . This method will be able to validate and store the user input. Since we are using a controller to do validation, validation failures are automatically redirected back to where it came from, and errors are flashed into session for us.

The $errors  Variable

In our tasks view, at resources/views/tasks/index.blade.php¬†, we used the @include('common.errors)¬† directive to render any validation errors that might occur. Let’s create the view now:

The $errors  variable is available in every Laravel view. It will be an empty instance of the viewErrorBag  object if no errors have occurred.

Creating The Task

With validation implemented, we are now going to add code to our TaskController@store  that will allow a task to be created, then redirect the user back to /tasks .

Using relationships between models will usually expose a create method, which accepts an array of attributes and will automatically set a foreign key, in the case the user_id ,  before adding the data to the database.  We can access this value using  $request->user() :

Display Existing Tasks

We will be using dependency injection to inject a TaskRepository (more on this below) into our TaskController .

Dependency Injection

Creating The Repository

The TaskRepository  will hold all our data access logic for the Task  model. This will make it simple to share Eloquent queries across the platform, if required in the future.

Create an app/Repositories  directory and add a TaskRepository  class.

Injecting The Repository

Now we have our repository defined, we will use it as a type-hint for our $tasks parameter of our Task constructor. We can then use it in our index route, to only return tasks for the current, authenticated, user. (Using the forUser  method that we created in the TaskRepository  file.

Displaying The Tasks

Now we will update our index.blade.php to include code to display the current tasks. Replace the <!-- TODO: Current Tasks -->  comment with the following code.

Deleting Tasks

Adding The Delete Button

We left a “TODO” note in our code where we will be adding the delete button. It will be in the shape of a small single-button form and will send a DELETE /task request to our TaskController@destroy method:

The method_field('DELETE')  function will generate the following hidden input:

This will allow us to spoof the form’s method so that we can respond to the form’s request using a Route::delete¬† route.

Route Model Binding

Remember our route declaration for the delete route? It is like this:

Laravel has a clever way to inject entire model instances into the route. It will automatically resolve type-hinted Eloquent models defined in the controller action. So our destroy  method can look like this:

Since the parameter $task¬† is type-hinted as type Task¬†, Laravel sees that it matches the {task}¬† segment of the route’s URI (above) and will automatically inject the model instance with an ID matching the vakue in the request URI. If a matching instance is not found, a 404 HTTP error will be generated.

Authorization

Now we have the Task¬† instance injected into the destroy method, but we still need to make sure that only the task’s owner can destroy the task. Otherwise anyone can try to make requests with random IDs to the /task/{task}¬† URL. We do this by using Laravel’s authorization capabilities.

Creating A Policy

Laravel uses small classes as “policies” for organizing authorization logic. Usually there is a policy for each model, so let’s use the Artisan CLI to generate a TaskPolicy¬† for our Task¬† model:

Now let’s add a destroy¬† method to the shiny new policy file which Laravel created for us in app/Policies/TaskPolicy.php¬†. This method will receive a User¬† instance and a Task¬† instance. The method, like all policy methods, should simply return true¬† or false¬†. In our case, the method will check if the user’s ID matches with the task’s user_id¬†:

HOWEVER!!! For some reason, $task->user_id  returns the user_id as a string, while $user->id  returns a integer. This means that the ===  evaluation always return a false  and therefore deleting a task is never authorized.

There are several ways to fix this, such as casting everything as integers  or using the == operator instead, but the most logical way that I found was to change the return  line as follows:

Now we need to associate this TaskPolicy¬† policy to our Task¬† model. Add the following line to the app/Providers/AuthServiceProvider.php¬† file’s ¬† $policies¬† property.

Authorizing The Action

Now that our policy is written and associated with the model, let’s use it in our TaskController@destroy¬† method. We will use the authorize method, which takes two arguments: the name of the policy we want to call, and the model instance that we are wanting to authorize. Edit you destroy method now so it looks like the code below:

If the action is authorized (i.e. our policy’s destroy¬†¬†method returned true¬†) then the code will continue normally, otherwise it will throw a 403 exception and an error page will be displayed.

Deleting The Task

Let’s finish this destroy¬† method by actually deleting the task. We use Eloquent’s delete method to delete¬† the model instance in the database, then redirect the user back to the /tasks¬† page:

 

This entry was posted in Dev, Laravel, PHP. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *