Modul Framework Laravel PDF

You might also like

Download as pdf or txt
Download as pdf or txt
You are on page 1of 117

MODUL FRAMEWORK LARAVEL

Oleh : Asep Wahyudin

21 Januari 2019
CONTENTS

Contents ................................................................................................................................................... 2

1 Create Laravel Project....................................................................................................................... 5

1.1 Turn On Detail Error Message .................................................................................... 6

2 Database ........................................................................................................................................... 7

2.1 Troubleshooting ......................................................................................................... 8

3 Model ............................................................................................................................................... 9

3.1 Table Manipulation .................................................................................................. 31

3.1.1 Example ............................................................................................................... 31

3.2 Mass Assignment ..................................................................................................... 33

3.3 Validation ................................................................................................................. 33

4 Eloquent ......................................................................................................................................... 36

4.1.1 Example ............................................................................................................................ 36

4.2 Insert Data ................................................................................................................ 36

4.3 Select Data ............................................................................................................... 36

4.3.1 Get all data and sort by specific column .............................................................. 37

4.3.2 Get data by id ...................................................................................................... 37

4.3.3 Get data by specific column ................................................................................. 37

4.3.4 Join data (Raw) .................................................................................................... 37

4.4 Edit a data ................................................................................................................ 38

4.5 Delete Data .............................................................................................................. 39

4.5.1 Delete multiple data ............................................................................................ 39

4.5.2 Delete data with condition .................................................................................. 39

4.6 Database Transaction ............................................................................................... 40

4.6.1 Manual Transaction ............................................................................................. 40

5 Relationship .................................................................................................................................... 42

5.1 One To One .............................................................................................................. 42

5.1.1 Example: .............................................................................................................. 42

2
5.2 One To Many ............................................................................................................ 43

5.2.1 Example ............................................................................................................... 44

5.3 Many to Many .......................................................................................................... 45

5.3.1 Example ............................................................................................................... 45

5.4 Implementation ....................................................................................................... 46

6 Controller .......................................................................................................................................... 9

6.1 Static Page .................................................................................................................. 9

6.1.1 Implementation ..................................................................................................... 9

6.2 Dynamic Page ........................................................................................................... 10

6.2.1 Implementation ................................................................................................... 10

7 View ................................................................................................................................................ 14

7.1 Layout....................................................................................................................... 20

7.2 Adding Extension...................................................................................................... 23

7.3 Setup View Structure for CRUD Articles ................................................................... 24

7.3.1 Setup View For Create Data ................................................................................. 26

7.3.2 Setup View For Show Record ............................................................................... 27

7.3.3 Setup View For Modify A Record ......................................................................... 28

7.3.4 Troubleshooting................................................................................................... 28

8 Routes ............................................................................................................................................. 14

8.1 Resource Routes ...................................................................................................... 14

8.1.1 Implementation ................................................................................................... 14

8.2 Root routes .............................................................................................................. 15

8.2.1 Example ............................................................................................................... 15

8.3 Custom routes .......................................................................................................... 15

8.3.1 Example ............................................................................................................... 15

8.4 Only & Except Routes ............................................................................................... 15

8.4.1 Example ............................................................................................................... 15

8.5 Route Service Provider ............................................................................................. 16

3
8.5.1 Example ............................................................................................................... 16

8.6 Middleware routes ................................................................................................... 17

8.6.1 Example ............................................................................................................... 17

8.7 Namespace routes ................................................................................................... 17

8.7.1 Example ............................................................................................................... 17

8.8 Named Routes .......................................................................................................... 17

8.8.1 Example ............................................................................................................... 17

9 Security ........................................................................................................................................... 63

9.1 Signup....................................................................................................................... 66

9.2 Login ......................................................................................................................... 71

9.3 Forgot Password ...................................................................................................... 77

9.4 Authorization ........................................................................................................... 88

10 Advance ..................................................................................................................................... 93

10.1 Pagination ................................................................................................................ 93

3.1.2 Example ............................................................................................................................ 93

10.2 Ajax........................................................................................................................... 94

10.3 Testing .................................................................................................................... 101

10.4 Creating Restful API................................................................................................ 106

10.4.1 Create laravel project .................................................................................... 106

10.4.2 Configure database ....................................................................................... 107

10.4.3 Generate model and migration ..................................................................... 107

10.4.4 Generate seeder ............................................................................................ 108

10.4.5 Add request transformer extension .............................................................. 109

10.4.6 Create controller, route, and transformer .................................................... 110

10.4.7 Test ................................................................................................................ 113

4
1. CREATE LARAVEL PROJECT

To create new laravel project via composer, use this:

$ composer create-project laravel/laravel <project name>


5.3.*

Now if you check the file and folder structure of the application (laravel version 5.3), it will look like
(Figure 1):

Figure 1 Laravel project file and folder structure

Description (Figure 1):

app/, is a folder to setup controller, model, middleware.

5
resources/, is a folder to put views of application.

config/, is a folder to setup connection to database, email, global rule app, auth.

database/, is folder for setup seed data, migration file.

.env, is a file to put username and password configuration of email, database, token app.

composer.json, is a folder to put all information about application, and add new plugin for
application.

storage/, is a folder to put cache, session.

routes/, is a folder to put route files.

public/, is a folder to put all file that can access by public.

1.1. Turn On Detail Error Message

1. If error happens and you get message like "Whoops, looks like something went wrong", and you
want see error detail, you need turn on debugger. Open file .env, and find APP_DEBUG then
change the value to true:

APP_DEBUG=true

APP_LOG_LEVEL=debug

2. Debugger used for tracing error, if there’s something wrong in your code. I recommended to use
plugin like laravel-debugbar that can be found at: https://github.com/barryvdh/laravel-
debugbar

6
2. DATABASE

Connection to the database in laravel handled by app/config/database.php file, but remember; never
edit the file directly because it will be hard to reconfigure the project environment, so the best place
to set the database is in the .env file, that located in the root project directory. Now open the .env
file, search group DB_*. That group is used for database configuration.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=<database_name>
DB_USERNAME=<user_name>
DB_PASSWORD=<password>

Save the .env file and check if your application has successfully connected to your database, on
terminal run :

cd <your_project_directory>
php artisan migrate

Migration is a feature in laravel that can help the developers


to automate creation of tables in database.

First migration will create migration table (that will be used to record migration history of the
project), users table, and forgot password user table on the database.

Now we will test if the application is working. Open terminal and run development server on your
root project folder, using this command:

php artisan serve

If the application successfully started, you will see this:

Laravel development server started on http://localhost:8000

7
That means Laravel development server successfully running. To check the application, you need to
open the browser and type on the address bar http://localhost:8000.

2.1. TROUBLESHOOTING

1. Driver not found, make sure you have install the php extension for your database, such as php-
pgsql or php-mysql,
2. Authentication fails, if that happens make sure your database settings in .env file is valid.

8
3. CONTROLLER

Controller used for handling request that send by view and routes, controller can contain methods
(create, read, update, delete data), eloquent query, email send, and validation that declared from
model.

To create new controller, use artisan commands (make:controller). The name of the controller must
be plural and capitalized each word without a space, usage of controller generator:

php artisan make:controller <ExamplesController>

3.1. STATIC PAGE

Static page is web page with static content that will not changes in a long time, the content usually
written manually directly in the html code.

3.1.1. IMPLEMENTATION

For example, lets create static controller:

php artisan make:controller StaticsController

Now let’s open the app/Http/controllers/StaticsController.php file and add a method to handle
static page, for example we will create method profile:

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
class StaticsController extends Controller
{
public function profile() {
return view('statics/profile');
}
}

9
3.2. DYNAMIC PAGE

Dynamic page is a web page with dynamic content that always changes, the content usually returns
from a database and rendered in view.

3.2.1. IMPLEMENTATION

For example, lets create articles controller to handle articles:

php artisan make:controller ArticlesController --resource

The output will be:

Controller created successfully.

Now let’s open the app/Http/controllers/ArticlesController.php file. Here in controller you will put
your eloquent query to manipulate data in the table, before creating CRUD method, make sure load
class name of the used model at the top of controller class, for example controller will use Article
model class:

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Article;
use Session;

3.2.1.1. LIST ARTICLES DATA

In Articles Controller modify function index into this:

public function index()


{
$articles = Article::all();
return view('articles.index')->with('articles', $articles);
}
Description:

 Article::all(), is eloquent query to get all data article.


 return view(), used to render views/articles/index.blade.php.
 with(), is an action to pass variable/s from controller to view.

10
3.2.1.2. ADD NEW ARTICLE

In Articles Controller we need to setup action creates and store.

Modify function create into this:

public function create()


{
return view('articles.create');
}

Description:

 return view(), used for rendering views/articles/create.blade.php.

Modify function store into this:

public function store(Request $request)


{
Article::create($request->all());
Session::flash("notice", "Article success created");
return redirect()->route("articles.index");
}
Description:

 $request->all(), used for getting all input data.


 return redirect()->route(), used for redirecting to specific route name.
 Session::flash(), use to show temporary message into view.

11
3.2.1.3. SHOW ARTICLE DATA

In Articles Controller modify function show into this:

public function show($id)


{
$article = Article::find($id);
return view('articles.show')->with('article', $article);
}
Description:

 Article::find(), is query for get data article base on id.


 return view(), is used for render page views/articles/show.blade.php

3.2.1.4. MODIFY ARTICLE DATA

In Articles Controller we need setup action edit and update.

In Articles Controller modify function edit into this:

public function edit($id)


{
$article = Article::find($id);
return view('articles.edit')->with('article', $article);
}

Description:

 return view(), used for render views/articles/edit.blade.php.


 with(), used for passing variable to view.

In Articles Controller modify function update into this:

public function update(Request $request, $id)


{
Article::find($id)->update($request->all());
Session::flash("notice", "Article success updated");
return redirect()->route("articles.show", $id);
}
Description:

 $request->all(), to get all inputted data. update(), used to change values in database.

12
3.2.1.5. DELETE DATA ARTICLE

In Articles Controller modify action destroy into this:

public function destroy($id)


{
Article::destroy($id);
Session::flash("notice", "Article success deleted");
return redirect()->route("articles.index");
}
Description:

 Article::destroy(), used to delete specific data by id.

Complete Resources:

 http://laravel.com/docs/5.3/controllers
 http://laravel.com/docs/5.3/responses

13
4. ROUTES

Routes are used to handle URL requests from inside or outside of our application, there are 3 files
under routes folder:

1. web.php is used for handling http request,


2. console.php is used for handling console request, and
3. api.php is used for handling api request.

4.1. RESOURCE ROUTES

4.1.1. IMPLEMENTATION

Resource routes is a route to handle CRUD in controller. open file routes/web.php and add:

Route::resource('articles','articlesController');

Save the file and check if articles routes have been successfully created, on terminal run:

php artisan route:list

the output should be like (Figure2):

Figure 2 Artisan route:list output

14
4.2. ROOT ROUTES

4.2.1. EXAMPLE

Root route is used for routing user request to default page of our application. The default root in
Laravel is the '/' sign:

Route::get('/', '<ControllerName>@<MethodName>');

Example:

Route::get('/', 'ArticlesController@index');

4.3. CUSTOM ROUTES

4.3.1. EXAMPLE

Custom route is used for creating a specific route that name and the controller will process, depend
on a specific condition:

Route::<httpMethod>('<urlName>', '<ControllerName>@<MethodName>');

Examples:

Route::get('/profile', 'StaticsController@profile');
Route::post('/login', 'SessionsController@login');
Route::put('/password-reset/{id}',
'SessionsController@password_reset');
Route::delete('/remove-baned', 'SessionsController@remove_baned');

4.4. ONLY & EXCEPT ROUTES

4.4.1. EXAMPLE

"Only" & "Except used for register a specific route from resources type routes.

Example for "only":

Route::resource('/articles', 'ArticlesController',
['only'=>['index']]);

That will result URL for articles "index".

15
Example for "except":

Route::resource('/articles', 'ArticlesController', ['except'=>['index',


'show', 'destroy']]);
That will result URL for articles "create", "store", "edit", "update".

4.5. ROUTE SERVICE PROVIDER

4.5.1. EXAMPLE

Route service provider is used for registering custom file routes, this one is used to handle specific
group routes. For example, creating new file routes/admin.php, and fill with this code:

Route::group(['namespace' => 'Admin'], function() {

Route::resource('articles', 'ArticlesController');

});

Next we need to register it into app/Providers/RouteServiceProvider.php file, and find


method mapWebRoutes() and modify into:

protected function mapWebRoutes()


{
Route::group([
'middleware' => 'web',
'namespace' => $this->namespace,
], function ($router) {

require base_path('routes/web.php');
require base_path('routes/admin.php');

});
}

16
4.6. MIDDLEWARE ROUTES

4.6.1. EXAMPLE

To assign middleware to all routes within a group, you may use the middleware key in the group
attribute array. Middleware are executed in the order they are listed in the array, example:

Route::group(['middleware' => 'auth'], function () {


Route::get('/', function () {
// Uses Auth Middleware
});

Route::get('user/profile', function () {
// Uses Auth Middleware
});
});

4.7. NAMESPACE ROUTES

4.7.1. EXAMPLE

Namespace use for grouping controller that usually related with role of a user, example:

Route::group(['namespace' => 'Admin'], function() {

Route::resource('articles', 'ArticlesController');

});

4.8. NAMED ROUTES

4.8.1. EXAMPLE

Named routes allow the convenient generation of URLs or redirects for specific routes. You may
specify a name for a route by chaining the name method onto the route definition:

Route::get('user/profile', 'UserController@showProfile')-
>name('profile');

17
Check with php artisan route:list, and make sure the route list
is displayed correctly.

Complete Resource: http://laravel.com/docs/5.3/routing

18
5. VIEW

View is used for user interface of application, serve information about data that saved in the
database, JavaScript, and stylesheet. In laravel 5, we can manually create view
at resources/views/<folder_name_plural >/view_name.blade.php. This tutorial will explain how to
create view with layout design, so we don’t have to repeat certain section on every view.

Let’s setup folder for css and js first, in this example we will using jQuery and bootstrap:

- laravel-blog/
-- resources/
---- views/
------ layouts/
-------- application.blade.php
------ shared/
-------- head_nav.blade.php
-------- left_nav.blade.php
-- public/
---- css/
------ bootstrap/
-------- bootstrap.css
------ material-design/
-------- bootstrap-material-design.css
-------- ripples.css
------ custom/
-------- layout.css
---- js/
------ bootstrap/
-------- bootstrap.js
------ material-design/
-------- material.js
-------- ripples.js
------ jquery/
-------- jquery-2.2.5.js
------ custom/
-------- layout.js

19
5.1. LAYOUT

Layout is use for grouping a view and working as skeleton of a view, inside this layout we will declare
global stylesheet and JavaScript. Create a file in resources/views/layouts/application.blade.php,
open that file and modify to:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta httpequiv="XUACompatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-
scale=1">
<title>Laravel 5</title>
<link href="/assets/css/bootstrap.css" rel="stylesheet" />
<link href="/assets/css/material-design/bootstrap-material-
design.css" rel="stylesheet" />
<link href="/assets/css/material-design/ripples.css"
rel="stylesheet" />
<link href="/assets/css/custom/layout.css" rel="stylesheet" />l
</head>
<body style="padding-top:60px;">
<!--bagian navigation-->
@include('shared.head_nav')
<!-- Bagian Content -->
<div class="container clearfix">
<div class="row row-offcanvas row-offcanvas-left ">
<!--Bagian Kiri-->
@include("shared.left_nav")

<!--Bagian Kanan-->
<div id="main-content" class="col-xs-12 col-sm-9 main pull-
right">
<div class="panel-body">
@if (Session::has('error'))
<div class="session-flash alert-danger">
{{Session::get('error')}}
</div>
@endif
@if (Session::has('notice'))
<div class="session-flash alert-info">
{{Session::get('notice')}}

20
</div>
@endif
@yield("content")
</div>
</div>
</div>
</div>
<script src="/assets/js/jquery/jquery-2.2.5.js"></script>
<script src="/assets/js/bootstrap/bootstrap.js"></script>
<script src="/assets/js/material-design/material.js"></script>
<script src="/assets/js/material-design/ripples.js"></script>
<script src="/assets/js/custom/layout.js"></script>
</body>
</html>
Description:

 @include('shared.head_nav'), will load views/shared/head_nav.blade.php.


 @include('shared.left_nav'), will load views/shared/left_nav.blade.php.
 @yield(“content”), will load all view that inside tag @section(“content”).
 {{ }}, is blade statement that will execute code php with escape html, if don't want escape html
you can use {!! !!}.
 Session::has(), will check if session flash with name notice or error exist or not.

After that we will setup shared view, create file head_nav.blade.php and left_nav.blade.php at
views/shared/ folder.

First let’s modify views/shared/head_nav.blade.php file:

<div class="navbar navbar-fixed-top navbar-default" role="navigation">


<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-
toggle="collapse" data-target=".navbar-collapse">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"/>
<span class="icon-bar"/>
<span class="icon-bar"/>
</button>
<a href="#" class = "navbar-brand">Laravel 5 App</a>
</div>
<div class="collapse navbar-collapse">

21
<ul class="nav navbar-nav navbar-right">
<li><a>Home</a></li>
<li><a>Profile</a></li>
<li><a>Article</a></li>
</ul>
</div>
</div>
</div>

Next modify views/shared/left_nav.blade.php file:

<div class="col-xs-12 col-sm-3 side pull-left sidebar-offcanvas"


id="sidebar" role="navigation">
<div class="list-group">
<h1> Jambal Ralavel </h1>
</div>
</div>

Let see if our layout working open views/welcome.blade.php file and modify into:

@extends("layouts.application")
@section("content")
<h1>Never Stop Learn, Rocking \m/</h1>
@stop
Description:

 @extends(), is used for load views/layouts/application.blade.php.


 @section(), is used for declare the content that will yield by application.blade.php.
 @stop, is close tag for @section().

This route is for displaying the welcome.blade.php:

Route::get('/', function() { return view('welcome') });

Setup custom js for layout, create public/assets/js/custom/layout.js file and add:

$.material.init();

22
Setup custom css for layout, create public/assets/css/custom/layout.css file and add:

body
{
padding-top: 50px;
background-color: #ffffff;
}

Let’s run the laravel server:

php artisan serve

5.2. ADDING EXTENSION

First add laravelcollective service, this plugin will handle link, form, csrf protection. Now open up
file laravel-blog/composer.json, at section 'require' add "laravelcollective/html": "5.3.*", the code
will look like :

"require": {
"php": ">=5.6.4",
"laravel/framework": "5.3.*",
"laravelcollective/html": "5.3.*"
},

next install that service with composer, on terminal (make sure position inside project folder) run:

composer update

Setup provider for laravelcollective, open file config/app.php on provider’s array block, add:

'providers' => [

Collective\Html\HtmlServiceProvider::class,

23
Setup alias class for laravelcollective, still in file config/app.php on aliases array block, add:

'aliases' => [

'Form' => Collective\Html\FormFacade::class,


'Html' => Collective\Html\HtmlFacade::class,

Lastly, lets run dumps autoloader, on terminal:

composer dumpautoload

Complete resources: https://laravelcollective.com/docs/5.3/html

5.3. SETUP VIEW STRUCTURE FOR CRUD ARTICLES

Let’s create folder articles in resources/views/articles folder, and make index.blade.php,


create.blade.php, edit.blade.php, show.blade.php file, so the structure will look like:

-- resources/

---- views/

------ layouts/

-------- application.blade.php

------ shared/

-------- head_nav.blade.php

-------- left_nav.blade.php

------ articles/

-------- index.blade.php

-------- list.blade.php

-------- create.blade.php

-------- edit.blade.php

-------- form.blade.php

-------- show.blade.php

24
Modify index.blade.php file, into:

@extends("layouts.application")
@section("content")
<div class="row">
<h2 class="pull-left">List Articles</h2>
{!! link_to(route("articles.create"), "Create", ["class"=>"pull-right
btn btn-raised btn-primary"]) !!}
</div>
@include('articles.list')
@stop

Description:

 {!! !!}, is used by blade for declare all function, class, helper.
 link_to(), is used for create link to specific page.
 $articles, is variable that sent from action index from articles controller.
 @include(), for load partial view.

Modify list.blade.php file, into:

@foreach($articles as $article)
<article class="row">
<h1>{!!$article->title!!}</h1>
<p>
{!! str_limit($article->content, 250) !!}
{!! link_to(route('articles.show', $article->id), 'Read More') !!}
</p>
</article>
@endforeach
Description:

@foreach(), is function for loop the array.

@endforeach, is function for close tag @foreach

Setup url on head_nav.blade.php file:

<li>{!! link_to(route('root'), "Home") !!}</li>


<li>{!! link_to(route('profile'), "Profile") !!}</li>
<li>{!! link_to(route('articles.index'), "Article") !!}</li>

25
5.3.1. SETUP VIEW FOR CREATE DATA

Modify create.blade.php file, into:

@extends("layouts.application")
@section("content")
<h3>Create a Article</h3>
{!! Form::open(['route' => 'articles.store', 'class' => 'form-
horizontal', 'role' => 'form']) !!}
@include('articles.form')
{!! Form::close() !!}
@stop
Description:

 Form::open(), here Form::open used to declare the form group.


 'route' => 'articles.store', is target of routes that will process the form group, make sure you
already setup resource routes for crud articles.
 Form::close(), is used for close tag of Form::open().

Modify form.blade.php file, into:

<div class="form-group">
{!! Form::label('title', 'Title', array('class' => 'col-lg-3 control-
label')) !!}
<div class="col-lg-9">
{!! Form::text('title', null, array('class' => 'form-control',
'autofocus' => 'true')) !!}
<div class="text-danger">{!! $errors->first('title') !!}</div>
</div>
<div class="clear"></div>
</div>

<div class="form-group">
{!! Form::label('content', 'Content', array('class' => 'col-lg-3
control-label')) !!}
<div class="col-lg-9">
{!! Form::textarea('content', null, array('class' => 'form-
control', 'rows' => 10)) !!}
<div class="text-danger">{!! $errors->first('content') !!}</div>

26
</div>
<div class="clear"></div>
</div>

<div class="form-group">
<div class="col-lg-3"></div>
<div class="col-lg-9">
{!! Form::submit('Save', array('class' => 'btn btn-raised btn-
primary')) !!}
{!! link_to(route('articles.index'), "Back", ['class' => 'btn btn-
raised btn-info']) !!}
</div>
<div class="clear"></div>
</div>
Description:

 Form::label, is used for creating label input form.


 Form::text(), is used for creating input form.
 $errors->first(), will show error if validation failed.
 Form::textarea(), is used to create textarea input.
 Form::submit(), is used to create button submit.

5.3.2. SETUP VIEW FOR SHOW RECORD

Modify file show.blade.php, into:

@extends("layouts.application")
@section("content")
<article class="row">
<h2>{!! $article->title !!}</h2>
<div>{!! $article->content !!}</div>
</article>
<div>
{!! Form::open(array('route' => array('articles.destroy', $article-
>id), 'method' => 'delete')) !!}
{!! link_to(route('articles.index'), "Back", ['class' => 'btn btn-
raised btn-info']) !!}
{!! link_to(route('articles.edit', $article->id), 'Edit', ['class'
=> 'btn btn-raised btn-warning']) !!}
{!! Form::submit('Delete', array('class' => 'btn btn-raised btn-
danger', "onclick" => "return confirm('are you sure?')")) !!}

27
{!! Form::close() !!}
</div>
@stop
Description:

 $article, is variable that sent from action show in articles controller.

5.3.3. SETUP VIEW FOR MODIFY A RECORD

Modify edit.blade.php file, into:


@extends("layouts.application")
@section("content")
<h3>Edit Article</h3>
{!! Form::model($article, ['route' => ['articles.update', $article-
>id], 'method' => 'put', 'class' => 'form-horizontal', 'role' =>
'form']) !!}
@include('articles.form')
{!! Form::close() !!}
@stop
Description:

 Form::model, is used to declare open form tag, but the Form::model is used for populating data
from controller automatically.

For localization we can follow this documentation:

 https://laravel.com/docs/5.3/localization
 https://laracasts.com/discuss/channels/tips/example-on-how-to-use-multiple-locales-in-your-
laravel-5-website

5.3.4. TROUBLESHOOTING

Asset not automatically load when modifying the javascript and css, that mean cache still hold the old
resource of the asset, to refresh the we can run:

php artisan assets:clean

Complete Resource: http://laravel.com/docs/5.3/blade

28
6. MODEL

Model used to validate input from view, communication between application, and database. Model in
laravel 5 can be created manually in <application_direcotry> / app / <your_model.php> or if we
want to create model automatically, use generator “php artisan” command, to check available
generator in application, open terminal then run:

php artisan

The output should be a list of available artisan command.

To create a new model we can use make:model, and for then name of a model must be singular and
the first charcter must be uppercase. To create a model using generator, use this command:

php artisan make:model <NameModelSingular> -m

The -m option is to generate migration file automatically.

Let’s create article model, on terminal type this:

php artisan make:model Article --migration

The output should be:

Model created successfully.

Created Migration: some_date_and_time_create_articles_table

29
The command will create two files the first is model article at app/Article.php and migration file at
database/migrations/ some_date_and_time_create_articles_table.php, open the migration file and
modify into this:

<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateArticlesTable extends Migration
{
public function up()
{
Schema::create('articles', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->text('content');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('articles');
}
}

Save that file, and in console run:

php artisan migrate

that command will execute all migration file that have not been executed, every file that was execute
will be registered in migration table, so the file will not execute twice.

Description:

 public function up(), is a function that will be called when we run: php artisan migrate.
 public function down(), is a function that will be called when we run: php artisan
migrate:rollback.
 $table->string('title'), is use to declare column title with string data type.
 $table->text('content'), is use to declare column content with text data type.

These are several data type that available in Laravel migration string, integer, char, date, dateTime,
double, float, text, etc.

30
6.1. TABLE MANIPULATION

6.1.1 EXAMPLE

We can generate our own migration file using this:

php artisan make:migration <name_file_migration> --


table=<name_tables>

Asides from creating we can also manipulate tables, for example is to add and drop column. Create a
migration file:

php artisan make:migration add_author_to_articles --


table=articles

Open the migration file and modify as follows:

class AddAuthorToArticles extends Migration


{
public function up()
{
Schema::table('articles', function (Blueprint $table) {
$table->string('author');
});
}
public function down()
{
Schema::table('articles', function (Blueprint $table) {
$table->dropColumn('author');
});
}
}
Description:

Schema::table, used to modify table structure.

31
Or another example we can rename column. Create a migration file:

php artisan make:migration rename_author_in_articles --


table=articles

Open the migration file and modify as follows:

class AddAuthorToArticles extends Migration


{
public function up()
{
Schema::table('articles', function (Blueprint $table) {
$table->renameColumn('author', 'writer');
});
}
public function down()
{
Schema::table('articles', function (Blueprint $table) {
$table->renameColumn('writer', 'author');
});
}
}
Description:

$table->renameColumn(), used for rename column.

Make sure to run php artisan migrate after setup file


migration, if not the table will not change.

32
6.2. MASS ASSIGNMENT

Mass Assignment used for handling data that can be saved into table, in laravel we use array
protected $fillable to handle mass assignment, this array should be placed on the model class. Next
we will allow 'title' and 'content', so it can be inserted into articles table, open the model Article and
modify as follows:

<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
protected $fillable = [
'title', 'content'
];
}

Description:

protected $fillable = [];, is an array that is use for listed all column that can be manipulated (insert or
update certain table).

6.3. VALIDATION

In laravel we can validate data in three places first on the model, second custom FormRequest class,
or third in the designated controller. To create custom FormRequest class:

php artisan make:request ArticleRequest

that command will create a file at app/Http/Requests/ArticleRequest.php. Open the file and modify
as follows:

<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ArticleRequest extends FormRequest
{
public function authorize()
{
return true;
}

33
public function rules()
{
$id = $this->article;
return [
'title' => 'required|unique:articles,title|max:255',
'content' => 'required|unique:articles,content|min:50'
];
}
public function messages()
{
return [
'title.required' => 'Title is required, at least fill a
character',
'title.unique' => 'Title must unique, take another title'
];
}
}

Description:

 public function messages(), use to handle custom message for every rule that set in validation, if
not available, laravel will use default error message.
 public function authorize(), is an action that use to handle authorization of a request (false:
check if request have authorize session, true: allow request don't have authorize session)
 public function rules(), is a place to put validation rules for every column name.

The validation need to be called manually in controller, below code is the simple usage of a form
request validation, on controller add:

use App\Http\Requests\ArticleRequest;
class ArticlesController extends Controller
{
......
.......
public function store(ArticleRequest $request)
{...}
public function update(ArticleRequest $request, $id)
{...}
.......
}
Description:

34
 Use App\Http\Requests\ArticleRequest, is path address to ArticleRequest.php file.
 ArticleRequest, is a request class name that will be used to create object request that need to be
validate.

Complete Resources:

 http://laravel.com/docs/5.3/validation
 https://laracasts.com/discuss/channels/requests/laravel-5-validation-request-how-to-
handle-validation-on-update

35
7. ELOQUENT

Eloquent is a library for handling data manipulation like create, update delete data from table. This
library will help for easier query, so we don't need to modify the query.

7.1. EXAMPLE

These are the examples how to use eloquent in laravel.

7.2. INSERT DATA

Eloquent:

$some_variable = new <model_name>;


$some_variable-><column_name> = <values>;
$some_variable->save();

Implementation example:

$new_article = new Article;


$new_article->title = "Learn Laravel";
$new_article->content = "lorem ipsum laravel ok";
$new_article->save();
Or:

Article::create($request->all());

7.3. SELECT DATA

Eloquent:

<model_name>::all();

Implementation example:

Article::all();

36
7.3.1. GET ALL DATA AND SORT BY SPECIFIC COLUMN

Eloquent:

<model_name>::all()->orderBy('<column_name>', '<desc/asc>');

Implementation example:

Article::all()->orderBy('title', 'desc');

7.3.2. GET DATA BY ID

Eloquent:

<model_name>::find(<id>);

Implementation example:

Article::find(1);

7.3.3. GET DATA BY SPECIFIC COLUMN

Eloquent:

<model_name>::where('<column_name>', '<values_for_compare>');

Implementation example:

Article::where('title', 'Learn Laravel');

7.3.4. JOIN DATA (RAW)

Eloquent:

DB::table('<table_name_one>')->join('<table_name_two>', '<parent_id>',
'=', '<foreign_id>')->get();
Implementation example:

DB::table('articles')->join('comments', 'articles.id', '=',


'comments.user_id')->get();

37
7.4. EDIT A DATA

Eloquent:

$some_variable = <model_name>::where('id', <id>)


->update(['<column_name>' => <value>, '<column_name>' => <value>]);
Implementation example:

$new_article = Article::where('id', 1)
->update([“title” => “Learn Laravel Edited”]);
Or

Eloquent:

$some_variable = <model_name>::find(<id>);
$some_variable-><column_name> = <values>;
$some_variable->save();

Implementation example:

$new_article = Article::find(1);
$new_article->title = "Learn Laravel Edited";
$new_article->save();

Or:

Article::find($id)->update($request->all());

38
7.5. DELETE DATA

Eloquent:

$some_variable = <name_model>::find(<id>);
$some_variable->delete();
Implementation example:

$new_article = Article::find(1);
$new_article->delete();
Or

Eloquent

<model_name>::destroy(<id>);

Implementation example:

Article::destroy(1);

7.5.1. DELETE MULTIPLE DATA

Eloquent:

<model_name>::destroy(<id>);

Implementation example:

Article::destroy([1, 3, 5]);

7.5.2. DELETE DATA WITH CONDITION

Eloquent:

<model_name>::where(<your_condition>)->delete();

Implementation example:

Article::where('score', '<', 6)->delete();

39
7.6. DATABASE TRANSACTION

Transaction used for handling exception when query is executed, this technique will prevent query or
queries to be executed before all condition is fulfilled.

Eloquent:

DB::transaction(function () {
//your query here
});

Implementation example:

DB::transaction(function () {
$id = DB::table('articles')->insertGetId($request->all());
DB::table('comments')->insert(['article_id'=>$id, 'content'=>'lorem
ipsum dolor c]);
});

7.6.1. MANUAL TRANSACTION

Eloquent:

DB::beginTransaction();
//your query here
DB::commit(); //this code is for executing the query
DB::rollBack(); //this code will cancel the query if exception
arise
Implementation example:

DB::beginTransaction();
try {
$id = DB::table('articles')->insertGetId($request->all());
DB::table('comments')->insert(['article_id'=>$id, 'content'=>'lorem
ipsum dolor c amet']);
} catch(\Exception $e) {
DB::rollBack();
}
DB::commit();

40
Complete Resources:

 http://laravel.com/docs/5.3/eloquent
 http://laravel.com/docs/5.3/queries
 https://laravel.com/docs/5.3/database

41
8. RELATIONSHIP

8.1. ONE TO ONE

One to one relationship is when a record in a table is exactly connect to one record in other table.

Parent Model:

public function relation_name_singular() {


return $this->hasOne('App\ModelName', 'foreign_key');
}

Child Model:

public function relation_name_singular() {


return $this->belongsTo('App\ParentModelName', 'foreign_key');
}

8.1.1. EXAMPLE:

Figure 3 One to one relationship

Model Husband.php:

public function wive() {


return $this->hasOne('App\Wive', 'husband_id');
}

42
Model Wive.php:

public function husband() {


return $this->belongsTo('App\Husband', 'husband_id');
}
Select a motor cycle base on employee:

$husband = Wive::find(1)->husband;

8.2. ONE TO MANY

One to Many relationship is when a record in a table can be reference as many on another table.

Parent Model:

public function relation_name_plular() {


return $this->hasMany('App\ChildModelName', 'foreign_key');
}

Child Model:

public function relation_name_singular() {


return $this->belongsTo('App\ParentModelName', 'foreign_key');
}

43
8.2.1. EXAMPLE

Figure 4 One to many relationship

Model Article.php:

public function comments() {


return $this->hasMany('App\Comment', 'article_id');
}
Model Comment.php:

public function article() {


return $this->belongsTo('App\Article', 'article_id');
}

Select all comment for an article:

$comments = Article::find(1)->comments;

44
8.3. MANY TO MANY

One to many is relationship between two table A and B in which A may contain a parent row for
which there are many children in B and vice versa.

Parent Model:

public function relation_name_plular() {


return $this->belongsToMany('App\ChildModelName', 'bridge_table',
'foreign_key_parent', 'foreign_key_child');
}
Child Model:

public function relation_name_plular() {


return $this->belongsToMany('App\ParentModelName', 'bridge_table',
'foreign_key_parent', 'foreign_key_child');
}

8.3.1. EXAMPLE

Figure 5 Many to many relationship

45
Model Doctor.php:

public function patients() {


return $this->belongsToMany('App\Patient, 'doctors_patients');
}
Model Patient.php:

public function doctors() {


return $this->belongsToMany('App\Doctor, 'doctors_patients');
}

Select all homes for a family:

$patients = Doctor::find(1)->patients;

8.4. IMPLEMENTATION

Here we will be using One to Many relationship, lets create new model:

php artisan make:model Comment -m

Open model Comment, then add:

public static function valid() {

return array(

'content' => 'required'

);

public function article() {

return $this->belongsTo('App\Article', 'article_id');

46
Open migration file for create_comments and modify to:

<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateComments extends Migration {
public function up()
{
Schema::create('comments', function(Blueprint $table)
{
$table->increments('id');
$table->integer('article_id');
$table->text('content');
$table->string('user');
$table->timestamps();
});
}
public function down()
{
Schema::drop('comments');
}
}
Description:

 article_id, is column that use as foreign key in relationship.

Save and execute that file, in terminal run:

php artisan migrate

After model we need to setup routes, open file routes/web.php and add:

Route::resource('comments', 'CommentsController');

Ok now we need to create comment controller, on terminal run:

php artisan make:controller CommentsController

47
Open app/http/controllers/CommentsController.php, and modify to this:

<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Comment, App\Article;
class CommentsController extends Controller {
public function store(Request $request)
{
$validate = Validator::make($request->all(), Comment::valid());
if($validate->fails()) {
return Redirect::to('articles/'. $request->article_id)
->withErrors($validate)
->withInput();
} else {
Comment::create($request->all());
Session::flash('notice', 'Success add comment');
return Redirect::to('articles/'. $request->article_id);
}
}
}

Next we need to modify view for article show, open resources/views/articles/show.blade.php, and
modify to:

@extends("layouts.application")
@section("content")
<div>
<h1>{!! $article->title !!}</h1>
<p>{!! $article->content !!}</p>
<i>By {!! $article->author !!}</i>
</div>
<div>
<h3><i><u>Give Comments</u></i></h3>
{!! Form::open(['route' => 'comments.store', 'class' => 'form-
horizontal', 'role' => 'form']) !!}
<div class="form-group">
{!! Form::label('article_id', 'Title', array('class' => 'col-lg-3
control-label')) !!}

48
<div class="col-lg-9">
{!! Form::text('article_id', $value = $article->id, array('class'
=> 'form-control', 'readonly')) !!}
</div>
<div class="clear"></div>
</div>
<div class="form-group">
{!! Form::label('content', 'Content', array('class' => 'col-lg-3
control-label')) !!}
<div class="col-lg-9">
{!! Form::textarea('content', null, array('class' => 'form-
control', 'rows' => 10, 'autofocus' => 'true')) !!}
{!! $errors->first('content') !!}
</div>
<div class="clear"></div>
</div>
<div class="form-group">
{!! Form::label('user', 'User', array('class' => 'col-lg-3
control-label')) !!}
<div class="col-lg-9">
{!! Form::text('user', null, array('class' => 'form-control'))
!!}
</div>
<div class="clear"></div>
</div>
<div class="form-group">
<div class="col-lg-3"></div>
<div class="col-lg-9">
{!! Form::submit('Save', array('class' => 'btn btn-primary'))
!!}
</div>
<div class="clear"></div>
</div>
{!! Form::close() !!}
</div>
@foreach($comments as $comment)
<div style="outline: 1px solid #74AD1B;">
<p>{!! $comment->content !!}</p>
<i>{!! $comment->user !!}</i>
</div>
@endforeach

49
@stop
Description:

 Form::Open(), the form will use for input comment and process in articles controller.
 @foreach(), the loop will use for load data comments that sent from action show in articles
controller.

Now we will setup validation and relationship in model article, open app/models/Article.php, and
add:

public static function valid() {


return array(
'content' => 'required'
);
}

public function comments() {


return $this->hasMany('App\Comment', 'article_id');
}

Next the last step is to modify action show, open app/controllers/ArticlesController.php:

public function show($id)


{
$article = Article::find($id);
$comments = Article::find($id)->comments-
>sortBy('Comment.created_at');
return view('articles.show')
->with('article', $article)
->with('comments', $comments);
}

Now run Laravel server and open an article, if you insert valid comment the list comments must show
below input form, otherwise error notification will be showed.

50
9. SECURITY - NATIVE

9.1 BASICS

1. Run the php artisan to create the Auth resource:

$ php artisan make:auth


Create the Role model and respective migration (-m parameter):

$ php artisan make:model Role -m

2. Edit CreateRolesTable class in the migrations folder:

public function up()

Schema::create(‘roles’, function (Blueprint $table) {


$table->increments(‘id’);
$table->string(‘name’);
$table->string(‘description’);
$table->timestamps();
});

public function down()

Schema::dropIfExists(‘roles’);

3. Create a new migration for the role_user pivot table:

$ php artisan make:migration create_role_user_table

Edit CreateRoleUserTable class in the migrations folder:

public function up()

Schema::create(‘role_user’, function (Blueprint $table)

$table->increments(‘id’);
$table->integer(‘role_id’)->unsigned();
$table->integer(‘user_id’)->unsigned();
});

public function down()

Schema::dropIfExists(‘role_user’);

4. Now let’s provide a many-to-many relationship between User and Role.

Open User model and add the following method:

public function roles()

return $this->belongsToMany(Role::class);

Do the same with Role model:

public function users()

return $this->belongsToMany(User::class);

5. It’s time to create some seeders to add roles and users in the database:

$ php artisan make:seeder RoleTableSeeder


$ php artisan make:seeder UserTableSeeder

Edit RoleTableSeeder class (database/seeds/ folder) adding the following code in run() method:

use Illuminate\Database\Seeder;
use App\Role;
class RoleTableSeeder extends Seeder
public function run()

$role_employee = new Role();


$role_employee->name = ‘employee’;
$role_employee->description = ‘A Employee User’;
$role_employee->save();
$role_manager = new Role();
$role_manager->name = ‘manager’;
$role_manager->description = ‘A Manager User’;
$role_manager->save();

Do the same with UserTableSeeder class:

use Illuminate\Database\Seeder;
use App\User;
use App\Role;
class UserTableSeeder extends Seeder

public function run()

$role_employee = Role::where(‘name’, ‘employee’)-


>first();
$role_manager = Role::where(‘name’, ‘manager’)-
>first();
$employee = new User();
$employee->name = ‘Employee Name’;
$employee->email = ‘employee@example.com’;
$employee->password = bcrypt(‘secret’);
$employee->save();
$employee->roles()->attach($role_employee);
$manager = new User();
$manager->name = ‘Manager Name’;
$manager->email = ‘manager@example.com’;
$manager->password = bcrypt(‘secret’);
$manager->save();
$manager->roles()->attach($role_manager);

Edit DatabaseSeeder class (database/seeds/ folder) adding the following code in run() method:

public function run()

// Role comes before User seeder here.


$this->call(RoleTableSeeder::class);
// User seeder will use the roles above created.
$this->call(UserTableSeeder::class);

6. Open User model and add these three tiny methods:

/**
* @param string|array $roles
*/
public function authorizeRoles($roles)

if (is_array($roles)) {
return $this->hasAnyRole($roles) ||
abort(401, 'This action is unauthorized.');

return $this->hasRole($roles) ||
abort(401, 'This action is unauthorized.');

/**
Check multiple roles
@param array $roles
*/
public function hasAnyRole($roles)
return null !== $this->roles()->whereIn(‘name’,
$roles)->first();

/**
Check one role
@param string $role
*/
public function hasRole($role)

return null !== $this->roles()->where(‘name’, $role)-


>first();

7. Open app/Http/Controllers/Auth/RegisterController.php and change the create() method to set a


default Role for new Users:

use App\Role;
class RegisterController ...
protected function create(array $data)

$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
$user
->roles()
->attach(Role::where('name', 'employee')-
>first());
return $user;

8. Run the migrate command with seed parameter. Next time you login, each user should have a
role.

$ php artisan migrate:fresh –seed


9. Finally, the final step! Now, all you need to do is call the User authorizeRoles() method inside
your Controller Actions or Middleware’s and pass an array with the user roles you want to grant
access.

class HomeController extends Controller

public function construct()

$this->middleware('auth');

public function index(Request $request)

$request->user()->authorizeRoles(['employee',
'manager']);
return view(‘home’);

/*
public function someAdminStuff(Request $request)

$request->user()->authorizeRoles('manager');
return view(‘some.view’);

*/

9.2 ADVANCE

9.2.1 CREATE MIDDLEWARE

We will create a new middleware CheckRole

php artisan make:middleware CheckRole

Modify the CheckRole.php file under app > Middleware

namespace App\Http\Middleware;
use Closure;

class CheckRole

/**
* Handle an incoming request.

@param $request
@param $next
* @return mixed
*/
public function handle($request, Closure $next,
$role)

if (! $request->user()->hasRole($role)) {
abort(401, 'This action is unauthorized.');

return $next($request);

We have modified the handle method middleware to check for given role.

Next step is to register the middleware we just created. Open Kernel.php which is located under App
> and modify array $routeMiddleware to include the role middleware.

protected $routeMiddleware = [
'auth' =>

'auth.basic' =>

ass,
'bindings' =>

'can' =>

'guest' =>
\App\Http\Middleware\RedirectIfAuthenticated::class,
'throttle' =>

'role' => \App\Http\Middleware\CheckRole::class,


];

9.2.2 MODIFY CONTROLLERS

Open AdminController.php. Below code in constructor method will check if the logged in user has role
manager role associated with it.

public function construct()

$this->middleware('auth');
$this->middleware('role:manager');

9.2.3 MORE THAN ONE ROLE

We can authorize more than one role using the middleware, just open it and edit it like this:

namespace App\Http\Middleware;

use Closure;

class CheckRole

/**
* Handle an incoming request.

@param $request
@param $next
* @return mixed
*/
public function handle($request, Closure $next,
...$role)

if (! $request->user()->authorizeRoles($role)) {
abort(401, 'This action is unauthorized.');
return $next($request);

Notice the three dots before the role, it will help us to create a flexible amount of argument and we
use the authorizeRoles function.

Now open your controller, we can use it like this:

public function construct()

$this->middleware('auth');
$this->middleware('role:manager, employee');

Or we can use it at our route:

Route::group(['middleware' => ['auth','role:manager']],


function () {

'admin\ManagerController');
});

9.3 EDITING EMAIL TEMPLATE

First don’t forget to edit your .env for email server address for verification or forget password feature.

If you want to make a custom email for this just follow these steps.

1. Create a notification

php artisan make:notification MailResetPasswordToken


edit this file which you find in a new folder App\Notifications

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;

class MailResetPasswordToken extends Notification

use Queueable;

public $token;

/**
Create a new notification instance.

@return void
*/
public function construct($token)

$this->token = $token;

/**
Get the notification's delivery channels.

@param mixed $notifiable


@return array
*/
public function via($notifiable)

return ['mail'];

/**
Get the mail representation of the notification.

@param mixed $notifiable


@return
\Illuminate\Notifications\Messages\MailMessage
*/
public function toMail($notifiable)
return (new MailMessage)
->subject("Reset your password")
->line("Hey, did you forget your
password? Click the button to reset it.")
->action('Reset Password',
url('password/reset', $this->token))
->line('Thankyou for being a
friend');

2. Override the send password reset trait with your local implementation in your User.php user
model

/**
* Send a password reset email to the user
*/
public function sendPasswordResetNotification($token)

$this->notify(new MailResetPasswordToken($token));

3. Remember to import the class at the top of the user model

use App\Notifications\MailResetPasswordToken ;

4. If you need to alter the layout of the message, including the text “If you’re having trouble clicking
the “Reset Password” button,” then you need to run:

php artisan vendor:publish

5. and then edit the files in

/resources/views/vendor/notifications
10. SECURITY - SENTINEL

In this tutorial we will try standard security, such as 'sign up', 'login', and 'forgot password'. We will be
using "Sentry" library, this library has complete features like authentication, authorization,
registration, user & role management.

To install Sentry open composer.json file and add:

"require": {
.....
"cartalyst/sentinel": "2.0.*"
},

After that, in terminal run:

composer update

Setup Provider & Aliases

After that, we need to add providers & aliases at config/app.php file, first setup providers:

Cartalyst\Sentinel\Laravel\SentinelServiceProvider::class,

next setup aliases:

'Activation' => Cartalyst\Sentinel\Laravel\Facades\Activation::class,


'Reminder' => Cartalyst\Sentinel\Laravel\Facades\Reminder::class,
'Sentinel' => Cartalyst\Sentinel\Laravel\Facades\Sentinel::class,

Save that file, and make sure our library successfully added. Now terminal run:

composer dumpautoload

php artisan optimize

Now we will setup migration. To publish migration file run command below:

php artisan vendor:publish --


The last command will create 2014_07_02_230147_migration_cartalyst_sentinel.php file.

Execute that migration file with:

php artisan migrate

if an error happens when running migration, make sure you don't have table users in your database
(perhaps you have migrated the default file migration the users and and password_reset), To
troubleshoot this error we will have to modify table "users" and delete table "password_reset"), if
table users was existed please modify 2014_07_02_230147_migration_cartalyst_sentinel.php, find
block create users like code below:

public function up()


{
......
....
Schema::create('users', function (Blueprint $table) {

$table->increments('id');
$table->string('email');
$table->string('password');
$table->text('permissions')->nullable();
$table->timestamp('last_login')->nullable();
$table->string('first_name')->nullable();
$table->string('last_name')->nullable();
$table->rememberToken();
$table->timestamps();
$table->engine = 'InnoDB';
$table->unique('email');
});

public function down() {


.......
.......

Schema::drop('users');
}
and change the code into:

public function up()


{
......
....
Schema::table('users', function (Blueprint $table) {

$table->text('permissions')->nullable();
$table->timestamp('last_login')->nullable();
$table->string('first_name')->nullable();
$table->string('last_name')->nullable();
$table->dropColumn('name');
});
Schema::drop('password_resets');
}

public function down() {


.......
.......

Schema::table('users', function (Blueprint $table) {

$table->dropColumn('permissions');
$table->dropColumn('last_login');
$table->dropColumn('first_name');
$table->dropColumn('last_name');
});
}

save that file and try to run "php artisan migrate" if there’s no error that means migration setup for
Sentinel is success.

for complete resource: https://cartalyst.com/manual/sentinel/2.0


10.1. SIGNUP

In Laravel User model will be automatically created, if you check in app/models/ you will find the
User.php file, if not you need generate your own User model with:

php artisan make:model User

Open that file and modify to:

<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $table = 'users';
protected $fillable = [
'email', 'password','first_name','last_name'
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
}
Description:

 protected $guarded, so the column id cannot modify by input.


 protected $fillable, so the column can modify via input.
After that we need to add user resources, open routes/web.php, and add:

Route::get('signup', 'UsersController@signup')->name('signup');
Route::post('signup', 'UsersController@signup_store')-
>name('signup.store');
Description:

 'except' => array(), this will not create path for index and destroy for user controller.

After we setup model we need rule to validate input form user, on terminal run:

php artisan make:request UserRequest

Open app/Http/Requests/UserRequest.php file, and modify into below:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UserRequest extends FormRequest


{
public function authorize()
{
return true;
}

public function rules()


{
$id = $this->user;
return [
'email' => 'required|email|unique:users,email,'.$id,
'password' => 'required|min: 8|confirmed',
'first_name' => 'required',
'last_name' => 'required'
];
}
}
Next we need to create user controller, on terminal run:

php artisan make:controller UsersController

Open app/controllers/UsersController.php file, then add new method signup and signup_store inside
class:

use Sentinel;
use Session;
use App\Http\Requests\UserRequest;
class UsersController extends Controller {
public function signup()
{
return view('users.signup');
}
public function signup_store(UserRequest $request)
{
//// below code will register and automatic activate account user
//Sentinel::register($request, true);
//// or
Sentinel::registerAndActivate($request);
Session::flash('notice', 'Success create new user');
return redirect()->back();
}
}

Add a link to “Sign Up” in header, open views/shared/head_nav.blade.php, and add:

<li>{!! link_to(route('signup'), 'Signup') !!}</li>


The last step you need setup view for signup, lets create view in
resources/views/users/signup.blade.php, and add:

@extends("layouts.application")

@section("content")

{!! Form::open(['route' => 'signup.store', 'class' => 'form-


horizontal', 'role' => 'form']) !!}

<div class="form-group">
{!! Form::label('first_name', 'First Name', array('class' =>
'col-lg-3 control-label')) !!}

<div class="col-lg-4">
{!! Form::text('first_name', null, array('class' => 'form-
control')) !!}
<div class="text-danger">{!! $errors->first('first_name')
!!}</div>
</div>
<div class="clear"></div>
</div>

<div class="form-group">
{!! Form::label('last_name', 'Last Name', array('class' => 'col-
lg-3 control-label')) !!}
<div class="col-lg-4">
{!! Form::text('last_name', null, array('class' => 'form-
control')) !!}
<div class="text-danger">{!! $errors->first('last_name')
!!}</div>
</div>
<div class="clear"></div>
</div>

<div class="form-group">
{!! Form::label('email', 'Email', array('class' => 'col-lg-3
control-label')) !!}
<div class="col-lg-4">
{!! Form::text('email', null, array('class' => 'form-control'))
!!}
<div class="text-danger">{!! $errors->first('email') !!}</div>
</div>
<div class="clear"></div>
</div>

<div class="form-group">
{!! Form::label('password', 'Password', array('class' => 'col-lg-
3 control-label')) !!}
<div class="col-lg-4">
{!! Form::password('password', array('class' => 'form-
control')) !!}
<div class="text-danger">{!! $errors->first('password')
!!}</div>
</div>
<div class="clear"></div>
</div>

<div class="form-group">
{!! Form::label('password_confirmation', 'Password Confirm',
array('class' => 'col-lg-3 control-label')) !!}
<div class="col-lg-4">
{!! Form::password('password_confirmation', array('class' =>
'form-control')) !!}
</div>
<div class="clear"></div>
</div>

<div class="form-group">
<div class="col-lg-3"></div>
<div class="col-lg-4">
{!! Form::submit('Signup', array('class' => 'btn btn-raised
btn-primary')) !!}
</div>
<div class="clear"></div>
</div>

{!! Form::close() !!}

@stop
Check if signup feature is working, go to: http://localhost:8000/signup

Create new user, if success it will redirect back to signup page with flash notification success, but if
not it will stay in the same page and give errors message under the input form.

Complete Resource: https://cartalyst.com/manual/sentinel/2.0#sentinel-register

10.2. LOGIN

Login will handle with sentinel method authentication that will automatically return true or false if
login attempt is executed. Let’s setup a routes for handling login, open routes/web.php and add:

Route::get('login', 'SessionsController@login')->name('login');

Route::post('login', 'SessionsController@login_store')-
>name('login.store');

Route::get('logout', 'SessionsController@logout')->name('logout');

Setup request class for handling login validation form, on terminal run:

php artisan make:request SessionRequest

Open the file (app/Http/Requests/SessionRequest.php) and modify into:

<?php
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class SessionRequest extends FormRequest


{

public function authorize()

{
return true;
}
public function rules()

{
return [
'email' => 'required',
'password' => 'required'
];
}

The sessions controller that will handle this process, lets create SessionsController, on terminal run:

php artisan make:controller SessionsController

Open that file app/controllers/SessionsController.php, then we need setup method for form login
and post login form:

use Sentinel;
use Session;
use App\Http\Requests\SessionRequest;
class SessionsController extends Controller
{
public function login()
{
if ($user = Sentinel::check())
{
Session::flash("notice", "You has login ".$user->email);
return redirect('/');
}
else
{
return view('sessions.login');
}
}

public function login_store(SessionRequest $request)


{
if($user = Sentinel::authenticate($request->all())) {
Session::flash("notice", "Welcome ".$user->email);
return redirect()->intended('/');
} else {
Session::flash("error", "Login fails");
return view('sessions.login');
}
}

public function logout() {


Sentinel::logout();
Session::flash("notice", "Logout success");
return redirect('/');
}
}
Description:

 Sentinel::authenticate, this method check for existing email and password in user table, if found
and correct, the method will create new login session.
 Sentinel::check, this method is for checking if current user session is present, if yes it will return
user object, if not it will return false.
 intended(), this method is for redirecting to intended route that was access, but have restriction
authentication, for example : if user click url to articles menu then user need to login first, after
successfully login user will be redirected to article.

Next we add login and logout link to our header, open app/views/shared/head_nav.blade.php:

@if (Sentinel::check())
<li>{!! link_to(route('logout'), 'Logout') !!}</li>
<li><a>Wellcome {!! Sentinel::getUser()->email !!}</a></li>
@else
<li>{!! link_to(route('signup'), 'Signup') !!}</li>
<li>{!! link_to(route('login'), 'Login') !!}</li>
@endif
Next we need to configure sentinel middleware that will be used by controller to check user
authentication, on terminal run:

php artisan make:middleware SentinelMiddleware

Open that file app/Http/Middleware/SentinelMiddleware.php, and modify block "handle" into:

<?php
......

use Sentinel;

class SentinelMiddleware
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
if (Sentinel::guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('login');
}
}
return $next($request);
}
}
Next we register sentinel middleware to route middleware, at file app/Http/Kernel.php:

protected $routeMiddleware = [
.....
.....
'sentinel' => \App\Http\Middleware\SentinelMiddleware::class,
];

Let’s implement the authentication in controller articles, so only the user that has login can access
this page. Open up file app/controllers/ArticlesController.php, and add:

.....
class ArticlesController extends Controller {
public function construct() {
$this->middleware('sentinel');
}
...........
.........
}
Description:

 function construct(), is constructor class.


 middleware(), this is method will process before action inside controller be execute.
 'sentinel', is middleware for checking authentication inside controller.

The last step is to setup view, create new file views/sessions/create.blade.php, and add:

@extends("layouts.application")

@section("content")

{!! Form::open(['route' => 'login.store', 'class' => 'form-


horizontal', 'role' => 'form']) !!}
<div class="form-group">
{!! Form::label('email', 'Email', array('class' => 'col-lg-3
control-label')) !!}
<div class="col-lg-4">
{!! Form::text('email', null, array('class' => 'form-control'))
!!}
<div class="text-danger">{!! $errors->first('email') !!}</div>
</div>
<div class="clear"></div>
</div>

<div class="form-group">
{!! Form::label('password', 'Password', array('class' => 'col-lg-
3 control-label')) !!}
<div class="col-lg-4">
{!! Form::password('password', array('class' => 'form-
control')) !!}
<div class="text-danger">{!! $errors->first('password')
!!}</div>
</div>
<div class="clear"></div>
</div>

<div class="form-group">
{!! Form::label('remember', 'Remember Me', array('class' => 'col-
lg-3 control-label')) !!}
<div class="col-lg-4">
{!! Form::checkbox('remember', null, array('class' => 'form-
control')) !!}
</div>
<div class="clear"></div>
</div>

<div class="form-group">
<div class="col-lg-3"></div>
<div class="col-lg-4">
{!! Form::submit('Login', array('class' => 'btn btn-raised btn-
primary')) !!}
</div>
<div class="clear"></div>
</div>
{!! Form::close() !!}

@stop
Next test the login and logout feature that we have created:

1. Start the server and try to access http://localhost:8000/articles and you will redirect to login.
2. Let’s login and make sure your login feature is working, if work you can access menu articles and
in header link login change to logout.
3. Let’s try to logout and if success will redirect to home.

Complete Resources:

 https://cartalyst.com/manual/sentinel/2.0
 https://laravel.com/docs/5.3/middleware
 https://laravel.com/docs/5.3/redirects

10.3. FORGOT PASSWORD

After setup the signup and login feature we will create feature forgot password and this feature will
help user to reset their password. The workflow is user must insert their registered email and if valid
and founded the application will create new forgot-token than will request to mail service (we will
using Mailgun or Mailchip, but in this example we will using Mailtrap) for send reset password
instruction. The change password will handle by Sentinel service the method that handle for reset
password is Reminder.

First lets setup email in our application, Laravel have an API Driver for communication to email
service, here we will using Guzzle ~6.0 Http library, open file <name_project>/composer.json and
inside require block add:

"require": {
………
"guzzlehttp/guzzle": "~6.0"

Save that file, then you need to update your composer in terminal:

composer update
Register new account to Mailtrap service https://mailtrap.io/register/signup or if you have account
you need login at https://mailtrap.io/signin, and if you have logged in click link "Demo Inbox" like
image bellow:

Figure 6 Mailtrap interface

And you will be redirected to Detail page SMTP setting:

Figure 7 Mailtrap settings list


Next we need setup SMTP to our project open .env file and find block code with extension MAIL_*,
and modify into this:

MAIL_DRIVER=smtp
MAIL_HOST=mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=k34l2kj09dsf9ert76kl
MAIL_PASSWORD=84klwe90j32l4kj903
MAIL_ENCRYPTION=null

Create class mailer for handling email notification to send reset password instruction, on terminal
run:

php artisan make:mail ReminderMailable

Open that file app/Mail/ReminderMailable.php, and modify it into:

......
.......
class ReminderMailable extends Mailable
{
use Queueable, SerializesModels;

public $detail;
public function construct($detail)
{
$this->detail = $detail;
}

public function build()


{
return $this->from('admin@md.com')
->subject('MD - Request reset password')
->view('emails.reminder')
->with([
'detail' => $this->detail,
]);
}
}
Description:

 $detail, is parameter that contain id, code (token that use by reminders table for reset password),
email
 emails.reminder, is view that use as template send email

setup email template for forgot password, create new file


resources/views/emails/reminder.blade.php, and fill with:

<body>
<h3>
Hello {!! $detail['email'] !!}
</h3>
<p>
Somebody request for changes your password,
<br />
if you dont please ignore this email,
<br />
but if you do, please click link below for futher intruction.
</p>
{!! link_to(route('reminders.edit', ['id' => $detail['id'], 'code' =>
$detail['code']]), 'Click me') !!}
<h2>Thanks</h2>
</body>
Complete Resources: http://laravel.com/docs/5.3/mail

After setup SMTP now we need setup the routes:

//this routes for check if email user is exist in database


Route::get('forgot-password', 'ReminderController@create')-
>name('reminders.create');
Route::post('forgot-password', 'ReminderController@store')-
>name('reminders.store');
//this routes for handle changes password
Route::get('reset-password/{id}/{token}', 'ReminderController@edit')-
>name('reminders.edit');
Route::post('reset-password/{id}/{token}',
'ReminderController@update')->name('reminders.update');
Let’s add link in Forgot Password in page login form, open file
resources/views/sessions/login.blade.php, and add:

.....
........
<div class="form-group">
<div class="col-lg-3"></div>
<div class="col-lg-4">
{!! Form::submit('Login', array('class' => 'btn btn-raised btn-
primary')) !!}
<br />
{!! link_to(route('reminders.create'), 'Forgot Password?') !!}
</div>
<div class="clear"></div>
</div>
.....
....
Description:

 link_to(route('reminders.create') .... , that link will target to reoute reminders.create that will
handle reset password.

Now we need setup new views for reset password, create file create.blade.php (this file will be used
for handling email address search and send reset password instruction), edit.blade.php (this file will
be used for setup new password), the folder structure will look like below:

-- resources/

---- views/

------ reminders/

-------- create.blade.php

-------- edit.blade.php
First let setup file create.blade.php, this form is to input email so if success this will send email that
contain reset password instruction:

@extends("layouts.application")
@section("content")
{!! Form::open(['route' => 'reminders.store', 'class' => 'form-
horizontal', 'role' => 'form']) !!}
<div class="form-group">
{!! Form::label('email', 'Email', array('class' => 'col-lg-3
control-label')) !!}
<div class="col-lg-4">
{!! Form::text('email', null, array('class' => 'form-control'))
!!}
<div class="text-danger">{!! $errors->first('email') !!}</div>
</div>
<div class="clear"></div>
</div>

<div class="form-group">
<div class="col-lg-3"></div>
<div class="col-lg-4">
{!! Form::submit('Submit', array('class' => 'btn btn-raised btn-
primary')) !!}
</div>
<div class="clear"></div>
</div>
{!! Form::close() !!}
@stop
Description:

 Form::open(['route'=>'reminders.store', ....), will target to action store at ReminderController, this


action will validate the email then if success will generate new code(forgot-token).

Second we need to setup file store.blade.php, this file use for input a new password user changes to:

@extends("layouts.application")
@section("content")
{!! Form::open(['route'=>['reminders.update', $id, $code], 'class' =>
'form-horizontal', 'role' => 'form']) !!}
<div class="form-group">
{!! Form::label('password', 'Password', array('class' => 'col-lg-3
control-label')) !!}
<div class="col-lg-4">
{!! Form::password('password', array('class' => 'form-control'))
!!}
<div class="text-danger">{!! $errors->first('password') !!}</div>
</div>
<div class="clear"></div>
</div>

<div class="form-group">
{!! Form::label('password_confirmation', 'Password Confirm',
array('class' => 'col-lg-3 control-label')) !!}
<div class="col-lg-4">
{!! Form::password('password_confirmation', array('class' =>
'form-control')) !!}
</div>
<div class="clear"></div>
</div>

<div class="form-group">
<div class="col-lg-3"></div>
<div class="col-lg-4">
{!! Form::submit('Submit', array('class' => 'btn btn-raised btn-
primary')) !!}
</div>
<div class="clear"></div>
</div>
{!! Form::close() !!}
@stop
Description:

 Form::open(['route'=>'reminders.update',. .. , this form will process to action update in controller


reminders, and need parameters id and code(forgot_token) that has generate and saved in table
reminders.
Next we create reminder controller that will be used for handling reset password process, on terminal
run:

php artisan make:controller ReminderController

Open that file app/Http/Controllers/ReminderController.php, into this:

<?php

namespace App\Http\Controllers;

use App\User;
use App\Http\Requests\ReminderRequest;
use Session, Event;
use Sentinel, Reminder;
use App\Events\ReminderEvent;

class ReminderController extends Controller


{
public function create() {
return view('reminders.create');
}

public function store(Request $request) {


$getuser = User::where('email', $request->email)->first();

if ($getuser) {
$user = Sentinel::findById($getuser->id);
($reminder = Reminder::exists($user)) || ($reminder =
Reminder::create($user));
Event::fire(new ReminderEvent($user, $reminder));
Session::flash('notice', 'Check your email for instruction');
} else {
Session::flash('error', 'Email not valid');
}
return view('reminders.create');
}

public function edit($id, $code) {


$user = Sentinel::findById($id);
if (Reminder::exists($user, $code)) {
return view('reminders.edit', ['id' => $id, 'code' => $code]);
}
else {
return redirect('/');
}
}

public function update(ReminderRequest $request, $id, $code) {


$user = Sentinel::findById($id);
$reminder = Reminder::exists($user, $code);

if ($reminder) {
Session::flash('notice', 'Your password success modified');
Reminder::complete($user, $code, $request->password);
return redirect('login');
} else {
Session::flash('error', 'Passwords must match.');
}
}
}
Description:

 Reminder::exists(), is sentinel method for check if current user has process reminder that wasn't
completed.
 Reminder::create(), is method for create new reminder process for specific user.
 Reminder::complete(), used for change user password into new password.
 Event::fire(), for call event listener for send email notification that contain reset password
instruction.
 ReminderRequest, used for validate form reset password.

Create ReminderRequest, on terminal run:

php artisan make:request ReminderRequest

Open that file and modify into:

<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ReminderRequest extends FormRequest
{
public function authorize()
{
return true;
}

public function rules()


{
return [
'password'=>'required|min:8|confirmed',
];
}
}

Next we create Event Listener, this listener will be used for handling reset password email notification
sender, to set event listener open app/Providers/EventServiceProvider.php, and add listener
mapping for reminder:

.......
.........
class EventServiceProvider extends ServiceProvider
{
protected $listen = [
'App\Events\ReminderEvent' => [
'App\Listeners\ReminderEmailSender',
],
];

public function boot()


.......
}

After that we need to generate file Event and Listener base on that mapping, on terminal run:

php artisan event:generate


You will get two new
files app/Events/ReminderEvent.php and app/Listeners/ReminderEmailSender.php. Now let’s
modify the file ReminderEvent.php:

<?php
........
use Sentinel, Reminder;
use App\User;
class ReminderEvent
{
use InteractsWithSockets, SerializesModels;
public $user;
public $reminder;

public function construct($user, $reminder)


{
$this->user = $user;
$this->reminder = $reminder;
}

public function broadcastOn()


........
}

And let’s modify the second file ReminderEmailSender.php:

<?php
use App\Events\ReminderEvent;
use Mail;
use App\Mail\ReminderMailable;
class ReminderEmailSender
{
public function construct()
......

public function handle(ReminderEvent $event)


{
$user = $event->user;
$reminder = $event->reminder;
$detail = [
'id' => $user->id,
'email' => $user->email,
'code' => $reminder->code,
];
Mail::to($user->email)->queue(new ReminderMailable($detail));
}
}
Description:

 ReminderEvent, is class event that handle reminder action for trigger process send email.
 Mail::to, is class for handle send email.
 queue, is method from Mail class that use for send process Mailer into queue.
 ReminderMailable, is class that handle send email notification for reset password.

10.4. AUTHORIZATION

Authorization used for limiting user access on specific feature. For this tutorial we will be using
authorization that provided by Sentinel service. First we need a seed data for role, user, role_user,
lets create seed data, om terminal run:

php artisan make:seed AuthorizeSeeder

Open that file that just generated that located at database/seeds/AuthorizeSeeder.php, and add:

<?php

use Illuminate\Database\Seeder;

class AuthorizeSeeder extends Seeder


{

public function run()


{

///// This for seed data admin


$role_admin = [
"slug" => "admin",
"name" => "Admin",
"permissions" => [
"admin" => true
]
];

Sentinel::getRoleRepository()->createModel()->fill($role_admin)-
>save();

$adminrole = Sentinel::findRoleByName('Admin');

$user_admin = ["first_name"=>"M", "last_name"=>"Admin",


"email"=>"madmin@mail.com", "password"=>"12345678"];

$adminuser = Sentinel::registerAndActivate($user_admin);

$adminuser->roles()->attach($adminrole);

///// this for seed data writer


$role_writer = [
"slug" => "writer",
"name" => "Writer",
"permissions" => [
"articles.index" => true,
"articles.create" => true,
"articles.store" => true,
"articles.show" => true,
"articles.edit" => true,
"articles.update" => true
]
];

Sentinel::getRoleRepository()->createModel()->fill($role_writer)-
>save();

$writerrole = Sentinel::findRoleByName('Writer');

$user_writer = ["first_name"=>"Oda", "last_name"=>"E",


"email"=>"oda@e.com", "password"=>"12345678"];

$writeruser = Sentinel::registerAndActivate($user_writer);
$writeruser->roles()->attach($writerrole);
}
}

From seed above writer only can access (index, show, create, store, edit, update) from article and
cannot delete data article, and for admin he has all privileges for CRUD article data, next we need
execute that file with command:

php artisan db:seed --class=AuthorizeSeeder

Middleware used for handle everything that related with authentication or authorization, on terminal
run:

php artisan make:middleware RoleSentinelMiddleware

Open that file app/Http/Middleware/RoleSentinelMiddleware.php, and modify to:

<?php

namespace App\Http\Middleware;

use Closure;

use Sentinel, Session;

class RoleSentinelMiddleware
{

public function handle($request, Closure $next)


{

if (Sentinel::inRole('writer') && Sentinel::getUser()-


>hasAccess([$request->route()->getName()])) {

return $next($request);
} elseif(Sentinel::getUser()->hasAccess('admin')) {

return $next($request);

} else {

Session::flash('error', 'You dont have privilege');

return redirect()->route('root');

}
}
}
Description:

 Sentinel::inRole(), use for check if current user is have role writer.


 Sentinel::getUser()->hasAccess(), use for check if current user is have a permission.
 $request->route()->getName(), for get routes name that will compare with permission that saved
in roles table.

Now let’s register the middleware to our application, open file kernel at app/Http/Kernel.php, open
that file then inside block array $routeMiddleware add class with name sentinel.role:

protected $routeMiddleware = [
....
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'sentinel' => \App\Http\Middleware\SentinelMiddleware::class,
'sentinel.role' =>
\App\Http\Middleware\RoleSentinelMiddleware::class,
];

Next after successfully setup middleware we need to implement that rule on controller articles, open
file ArticlesController.php, and add:

....

class ArticlesController extends Controller

{
public function construct() {

$this->middleware('sentinel');

$this->middleware('sentinel.role');

....

Lastly don’t forget to run:

composer dumpautoload

Now let’s check if all configuration working, first login with role as writer and check if you can create,
read, update article and if you try delete article you will get error message.

Now try login as role admin and if you try create, read, update, delete you will get no problem.

Complete resources:

 https://laravel.com/docs/5.3/middleware
 https://cartalyst.com/manual/sentinel/2.0#roles
11. ADVANCE

11.1 PAGINATION

To use auto pagination in laravel, just use paginate method in controller, and render method in view.

11.1.1 EXAMPLE

Controller:

$articles = Article::paginate(3);

return view('articles.index')->with('articles', $articles);

View:

<div>
{!! link_to('articles/create', 'Write Article', array('class' => 'btn
btn-raised btn-success')) !!}
</div>
@foreach ($articles as $article)
<div>
<p>{!! $article->id !!} </p>
<h1>{!! $article->title !!}</h1>
<p>
{!! $article->content !!}
</p>
<i>By {!! $article->author !!}</i>
<div>
@if(Auth::user()->role == 'reader')
{!! link_to('articles/'.$article->id, 'Show', array('class' => 'btn
btn-info')) !!}
@else
{!! link_to('articles/'.$article->id, 'Show', array('class' => 'btn
btn-info')) !!}
{!! link_to('articles/'.$article->id.'/edit', 'Edit', array('class'
=> 'btn btn-warning')) !!}
{!! Form::open(array('route' => array('articles.destroy', $article-
>id), 'method' => 'delete')) !!}
{!! Form::submit('Delete', array('class' => 'btn btn-danger',
"onclick" => "return confirm('are you sure?')")) !!}
{!! Form::close() !!}
@endif
</div>
</div>
@endforeach
<div>
{!! $articles->render() !!}
</div>

11.2 AJAX

In this session we will be using ajax for searching articles, pagination, and sorting, so when user click
search, sort by id, related articles will be showed without refreshing page.

Let’s open layout/application.blade.php and modify into:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta httpequiv="XUACompatible" content="IE=edge">
<meta name="viewport" content="width=devicewidth, initialscale=1">
<title>Lara Blog</title>
<link href="/css/bootstrap.css" rel="stylesheet" />
<link href="/css/bootstrap-material-design.css" rel="stylesheet" />
<link href="/css/ripples.css" rel="stylesheet" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-
awesome/4.5.0/css/font-awesome.min.css">
</head>
<body style="padding-top:60px;">
<!--bagian navigation-->
@include('shared.head_nav')
<!-- Bagian Content -->
<div class="container clearfix">
<div class="row row-offcanvas row-offcanvas-left ">
<!--Bagian Kiri-->
@include("shared.left_nav")
<!--Bagian Kanan-->
<div id="main-content" class="col-xs-12 col-sm-9 main pull-
right">
<div class="panel-body">
@if (Session::has('error'))
<div class="session-flash alert-danger">
{!!Session::get('error')!!}
</div>
@endif
@if (Session::has('notice'))
<div class="session-flash alert-info">
{!!Session::get('notice')!!}
</div>
@endif

<div class="row">
<div class="form-group label-floating">

<label class="col-lg-2" for="keywords">Search


Article</label>

<div class="col-lg-8">
<input type="text" class="form-control" id="keywords"
placeholder="Type search keywords">
</div>

<div class="col-lg-2">
<button id="search" class="btn btn-info btn-flat"
type="button">
Search
</button>
</div>

<div class="clear"></div>

</div>
</div>
<br />
<p>Sort articles by : <a id="id">ID &nbsp;<i id="ic-
direction"></i></a></p>
<br />
<div id="data-content">
@yield("content")
</div>
<input id="direction" type="hidden" value="asc" />
</div>
</div>
</div>
</div>
<script src="/js/jquery-1.12.3.js"></script>
<script src="/js/bootstrap.js"></script>
<script src="/js/material.js"></script>
<script src="/js/ripples.js"></script>
<script>
$.material.init();
$.material.checkbox();
</script>
<!-- Handle ajax link in header menu -->
<script>
$('#article_link').click(function(e){
e.preventDefault();
$.ajax({
url:'/articles',
type:"GET",
dataType: "json",
success: function (data)
{
$('#data-content').html(data['view']);
},
error: function (xhr, status)
{
console.log(xhr.error);
}
});
});
</script>

<!-- This for handle ajax pagination -->


<script>
$(document).ready(function() {
$(document).on('click', '.pagination a', function(e) {
get_page($(this).attr('href').split('page=')[1]);
e.preventDefault();
});
});
function get_page(page) {
$.ajax({
url : '/articles?page=' + page,
type : 'GET',
dataType : 'json',
data : {
'keywords' : $('#keywords').val(),
'direction' : $('#direction').val()
}
success : function(data) {
$('#data-content').html(data['view']);
$('#keywords').val(data['keywords']);
$('#direction').val(data['direction']);
},
error : function(xhr, status, error) {
console.log(xhr.error + "\n ERROR STATUS : " + status + "\n"
+ error);
},
complete : function() {
alreadyloading = false;
}
});
}
</script>

<!-- This for handle ajax search -->


<script>
$('#search').on('click', function(){
$.ajax({
url : '/articles',
type : 'GET',
dataType : 'json',
data : {
'keywords' : $('#keywords').val(),
'direction' : $('#direction').val()
},
success : function(data) {
$('#data-content').html(data['view']);
$('#keywords').val(data['keywords']);
$('#direction').val(data['direction']);
},
error : function(xhr, status) {
console.log(xhr.error + " ERROR STATUS : " + status);
},
complete : function() {
alreadyloading = false;
}
});
});
</script>
<!-- this js for handle ajax sorting -->
<script>
$(document).ready(function() {
$(document).on('click', '#id', function(e) {
sort_articles();
e.preventDefault();
});
});
function sort_articles() {
$('#id').on('click', function() {
$.ajax({
url : '/articles',
typs : 'GET',
dataType : 'json',
data : {
'keywords' : $('#keywords').val(),
'direction' : $('#direction').val()
},
success : function(data) {
$('#data-content').html(data['view']);
$('#keywords').val(data['keywords']);
$('#direction').val(data['direction']);

if(data['direction'] == 'asc') {
$('i#ic-direction').attr({class: "fa fa-arrow-up"});
} else {
$('i#ic-direction').attr({class: "fa fa-arrow-down"});
}
},
error : function(xhr, status, error) {
console.log(xhr.error + "\n ERROR STATUS : " + status +
"\n" + error);
},
complete : function() {
alreadyloading = false;
}
});
});
}
</script>
</body>
</html>

Next we modify ArticlesController.php, open the file and modify function index into:

function index(Request $request) {


if($request->ajax()) {
$articles = Article::where('title', 'like', '%'.$request-
>keywords.'%')
->orWhere('content', 'like', '%'.$request->keywords.'%');
if($request->direction) {
$articles = $articles->orderBy('id', $request->direction);
}
$articles = $articles->paginate(3);

$request->direction == 'asc' ? $direction = 'desc' : $direction =


'asc';
$request->keywords == '' ? $keywords = '' : $keywords = $request-
>keywords;

$view = (String) view('articles.list')


->with('articles', $articles)
->render();
return response()->json(['view' => $view, 'direction' =>
$direction, 'keywords' => $keywords, 'status' => 'success']);
} else {
$articles = Article::paginate(3);
return view('articles.index')
->with('articles', $articles);
}
}
Open index.blade.php and modify into:

@extends("layouts.application")
@section("content")
<div id="articles-list">
@include('articles.list')
</div>
@stop

Open list.blade.php and modify into:

<div>
{!! link_to('articles/create', 'Write Article', array('class' => 'btn
btn-raised btn-success')) !!}
</div>
@foreach ($articles as $article)
<div>
<p>{!! $article->id !!} </p>
<h1>{!! $article->title !!}</h1>
<p>
{!! $article->content !!}
</p>
<i>By {!! $article->author !!}</i>
<div>
@if(Auth::user()->role == 'reader')
{!! link_to('articles/'.$article->id, 'Show', array('class' => 'btn
btn-info')) !!}
@else
{!! link_to('articles/'.$article->id, 'Show', array('class' => 'btn
btn-info')) !!}
{!! link_to('articles/'.$article->id.'/edit', 'Edit', array('class'
=> 'btn btn-warning')) !!}
{!! Form::open(array('route' => array('articles.destroy', $article-
>id), 'method' => 'delete')) !!}
{!! Form::submit('Delete', array('class' => 'btn btn-danger',
"onclick" => "return confirm('are you sure?')")) !!}
{!! Form::close() !!}
@endif
</div>
</div>
@endforeach
<div>
{!! $articles->render() !!}
</div>

Now try to test what we have created.

More Resources:

Process Form:

 http://laravel.io/forum/03-30-2015-how-to-submit-form-via-ajax-in-laravel-5
 http://stackoverflow.com/questions/32467626/how-do-i-post-a-form-in-laravel-5-using-ajax

Pagination:

 https://gist.github.com/tobysteward/6163902
 http://laravel.io/forum/02-07-2014-advanced-ajax-pagination-what-to-do-when-there-is-option-
to-show-5102550-itesm-per-page-and-there-are-delete-operations-as-well

11.3 TESTING

Here we will be using functional test, and for testing controller that will be test is “articles” that we
have created, and the steps are:

1. Setup faker data with service fzaninotto.


2. Create test file inside folder 'app/tests'.
3. Setup phpunit in machine.

First lets install service fzaninotto open file composer.json and inside block require-dev add:

"fzaninotto/faker": "v1.4.0"

Then open terminal (make sure you have move to application path) then run:

composer update
Before we begin let's see the file ArticlesController.php that we have created before, From the
controller we will create Functional test, and the details are:

 Check if action index working: response success/200, will render index view page.
 Check if action create working: response success/200, will render create view page.
 Check if action store fails: response with redirect/302, redirect to create view page.
 Check if action store working: response with redirect/302, redirect to article index view page,
with success message.
 Check if action show working: response success/200, will render show view page.
 Check if action edit working: response success/200, render edit view page.
 Check if action update fails: response with redirect/302, redirect to edit view page.
 Check if action update working: response with redirect/302, redirect to article index view page,
send success message.

Let’s create file app/tests/ArticlesTest.php, and add code for test:

<?php
class ArticlesTest extends TestCase {
/* This testing Controller Articles
* All action for Create, Update, Delete, Show
* Data from Test will direct save to real database
*/

//TEST ACTION INDEX


public function testArticleIndex() {
$this->call('GET', 'articles');
$this->assertResponseOk(); //this equal with : $this-
>assertResponseStatus(200);
$this->assertViewHas('articles');
}

//TEST ACTION CREATE


public function testArticleCreate() {
$this->call('GET', 'articles/create');
$this->assertResponseOk();
}

//TEST ACTION STORE (WITH FAILS SCHEM)


public function testArticleStoreFails() {
$data = array("title" => "", "content" => "Lorem ipsum dolor sit
amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua.", "author" => "Ujang");
$post = $this->action('POST', 'ArticlesController@store', $data);
$this->assertRedirectedToRoute('articles.create');
}

//TEST ACTION STORE (WITH SUCCESS SCHEM)


public function testArticleStoreSuccess() {
$data = array("title" => "Testing Article title ".str_random(10),
"content" => str_random(10)." Lorem ipsum dolor sit amet, consectetur
adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua.", "author" => "Ujang");
$post = $this->action('POST', 'ArticlesController@store', $data);
$this->assertResponseStatus(302);
$this->assertRedirectedToRoute('articles.index');
$this->assertSessionHas('flash');
}

//TEST ACTION SHOW


public function testArticleShow() {
$article = Article::where('title', 'like', '%Testing Article
title%')->first();
if(empty($article)) {
$data = array("title" => "Testing Article title", "content" =>
"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.", "author"
=> "Ujang");
$post = $this->action('POST', 'ArticlesController@store', $data);
}
$this->action('GET', 'ArticlesController@show', $article->first()-
>id);
$this->assertResponseOk();
}

//TEST ACTION EDIT


public function testArticleEdit() {
$article = Article::where('title', 'like', '%Testing Article
title%')->first();
if(empty($article)) {
$data = array("title" => "Testing Article title", "content" =>
"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.", "author"
=> "Ujang");
$post = $this->action('POST', 'ArticlesController@store', $data);
}
$this->action('GET', 'ArticlesController@edit', $article->first()-
>id);
$this->assertResponseOk();
}

//TEST ACTION UPDATE (WITH FAILS SCHEM)


public function testArticleUpdateFails() {
$data = array("title" => "Testing Article title", "content" =>
"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.", "author"
=> "Ujang");
$post = $this->action('POST', 'ArticlesController@store', $data);
$article = Article::where('title', 'like', 'Testing Article
title')->first();
$update_data = array("title" => "", "content" => "Lorem ipsum dolor
sit amet, consectetur adipisicing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua.", "author" => "Ujang");

$this->call('PUT', 'articles/'.$article->first()->id,
$update_data);
$this->assertRedirectedTo('articles/'.$article->first()-
>id.'/edit');
}

//TEST ACTION UPDATE (WITH SUCCESS SCHEM)


public function testArticleUpdateSuccess() {
$article = Article::where('title', 'like', 'Testing Article
title')->first();
if(empty($article)) {
$data = array("title" => "Testing Article title", "content" =>
"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do
eiusmod tempor incididunt ut labore et dolore magna aliqua.", "author"
=> "Ujang");
$post = $this->action('POST', 'ArticlesController@store', $data);
}
$update_data = array("title" => "Edit Article Testing " .
str_random(10), "content" => str_random(10)."Lorem ipsum dolor sit
amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut
labore et dolore magna aliqua.", "author" => "Ujang");
$this->call('PUT', 'articles/'.$article->first()->id,
$update_data);
$this->assertRedirectedTo('articles');
$this->assertSessionHas('flash');
}
}

Save that file, then if you will run the test file we need phpunit, if your machine didn’t have it lets
install it, open terminal and run:

sudo apt-get install phpunit

Ater installing phpunit you can run test, on terminal run:

phpunit

The result will be like this:

PHPUnit 3.7.28 by Sebastian Bergmann.

Configuration read from /home/user/project_folder/phpunit.xml

.........

Time: 4.45 seconds, Memory: 26.25Mb

OK (9 tests, 17 assertions)

Complete Resources:

 official laravel doc: http://laravel.com/docs/testing


 faker doc: https://github.com/fzaninotto/Faker
 php unit: https://phpunit.de/
11.4 CREATING RESTFUL API

Application program interface (API) is a set of routines, protocols, and tools for building software
applications. An API specifies how software components should interact. Additionally, APIs are used
when programming graphical user interface (GUI) components.

A RESTful API is an application program interface (API) that uses HTTP requests to GET, PUT, POST
and DELETE data.

Steps:

1. Create laravel project.


2. Configure database.
3. Generate model and migration.
4. Generate seeder.
5. Add request transformer extension.
6. Create controller and route.
7. Test.

11.4.1 CREATE LARAVEL PROJECT

Go to Console and run:

composer create-project laravel/laravel <nama_project> 5.3.*

Wait for a while, because composer will download the necessary package for laravel project. When
finished, test if the application successfully created by running it:

cd <project_name>

php artisan serve

Check in browser: localhost: 8000


11.4.2 CONFIGURE DATABASE

Create database and edit .env file:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=<database_name>
DB_USERNAME=<user_name>
DB_PASSWORD=<password>

11.4.3 GENERATE MODEL AND MIGRATION

Go to Console and run:

php artisan make:model Task -m

Open the migration file that has been generated in


app/database/migrations/SOME_DATE_create_tasks_table.php and add:

public function up()


{
Schema::create('tasks', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->text('description');
$table->integer('user_id');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('tasks');
}
11.4.4 GENERATE SEEDER

We will generate user and task data in the database using seeder for testing our API. Now go to
Console and run these 2 command to create user and task seeder files:

php artisan make:seeder UsersTableSeeder

php artisan make:seeder TasksTableSeeder

Open the app/database/seeds/UsersTableSeeder file, and add:

public function run()


{
factory(App\User::class, 50)->create();
}

Open the app/database/seeds/TasksTableSeeder file, and add:

public function run()


{
factory(App\Task::class, 50)->create();
}

Open the app/database/seeds/DatabaseSeeder file, and add:

public function run()


{
$this->call(UsersTableSeeder::class);
$this->call(TasksTableSeeder::class);
}

Open the app/database/factories/ModelFactory.php file, and add:

$factory->define(App\User::class, function (Faker\Generator $faker) {


return [
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'password' => bcrypt('secret'),
'remember_token' => str_random(10),
];
});

$factory->define(App\Task::class, function (Faker\Generator $faker) {


$users = App\User::pluck('id')->toArray();
return [
'name' => $faker->unique()->name,
'description' => $faker->text,
'user_id' => $faker->randomElement($users)
];
});

Now execute the migrations and the seeds

php artisan migrate --seed

11.4.5 ADD REQUEST TRANSFORMER EXTENSION

Open the composer.json file, and add on the require part:

"ellipsesynergie/api-response": "^0.12.3",

Open the config/app.php file, and add on the providers part:

EllipseSynergie\ApiResponse\Laravel\ResponseServiceProvider::class,

Now run update to download related package:

Composer update
11.4.6 CREATE CONTROLLER, ROUTE, AND TRANSFORMER

Go to Console and run:

php artisan make:controller TaskController

Open route file at routes/api.php, and add:

// get list of tasks


Route::get('tasks','TaskController@index');
// get specific task
Route::get('task/{id}','TaskController@show');
// delete a task
Route::delete('task/{id}','TaskController@destroy');
// update existing task
Route::put('task','TaskController@store');
// create new task
Route::post('task','TaskController@store');

Open task controller file at app/http/controller/TaskController.php, and add:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests;
use EllipseSynergie\ApiResponse\Contracts\Response;
use App\Task;
use App\Transformer\TaskTransformer;

class TaskController extends Controller


{
protected $response;

public function construct(Response $response)


{
$this->response = $response;
}
public function index()
{
//Get all task
$tasks = Task::paginate(15);
// Return a collection of $task with pagination
return $this->response->withPaginator($tasks, new
TaskTransformer());
}

public function show($id)


{
//Get the task
$task = Task::find($id);
if (!$task) {
return $this->response->errorNotFound('Task Not Found');
}
// Return a single task
return $this->response->withItem($task, new
TaskTransformer());
}

public function destroy($id)


{
//Get the task
$task = Task::find($id);
if (!$task) {
return $this->response->errorNotFound('Task Not Found');
}

if($task->delete()) {
return $this->response->withItem($task, new
TaskTransformer());
} else {
return $this->response->errorInternalError('Could not
delete a task');
}

public function store(Request $request) {


if ($request->isMethod('put')) {
//Get the task
$task = Task::find($request->task_id);
if (!$task) {
return $this->response->errorNotFound('Task Not
Found');
}
} else {
$task = new Task;
}

$task->id = $request->input('task_id');
$task->name = $request->input('name');
$task->description = $request->input('description');
$task->user_id = 1; //or $request->user()->id;

if($task->save()) {
return $this->response->withItem($task, new
TaskTransformer());
} else {
return $this->response->errorInternalError('Could not
updated/created a task');
}

}
}

Create a Transformer folder inside the app folder and create a file named TaskTransformer.php
inside it, and modify that file as follows:

<?php

namespace App\Transformer;

class TaskTransformer {
public function transform($task) {
return [
'id' => $task->id,
'task' => $task->name,
'description' => $task->description
];
}
}

11.4.7 TEST

Test the API that we have created by using browser extension such as postman, rested, etc.
11.5 DEPLOYMENT

Here are the keys (and sometimes easy to overlook!) steps on deploying laravel application.

1. Login to server using ssh ($ ssh user@example.com)


2. Install PHP, Apache HTTP server, and MySQL.
3. Enable mod_rewrite for Apache.
4. Install Composer globally.
5. Create or pull your Laravel project in user directory.
6. Set permissions for Laravel folders.
7. Set up an Apache virtual host for your Laravel project.
8. Add new virtual host to hosts file.
9. Enable new virtual host and (optionally) disable the default virtual host.

11.5.1 INSTALL PHP, APACHE HTTP SERVER, AND MYSQL.

To install PHP, including everything needed to support Laravel framework, on Ubuntu-based Linux
system, such as Vagrant, run the following commands in the terminal/shell.

$ sudo apt-get update


$ sudo apt-get install curl php php-curl php-cli php-mysql php-mcrypt
php-mbstring php-gettext php-gd php-zip
$ sudo apt-get install apache2 libapache2-mod-php
$ sudo apt-get -y install mysql-server

11.5.2 ENABLE MOD_REWRITE FOR APACHE.

One of the most frequently encountered difficulties when starting with Laravel on Apache HTTP
server is that the mod_rewrite extension is not enabled. Laravel requires mode_rewrite to properly
transform URLs to be interpreted by its routing function via .htaccess. On some Ubuntu platforms,
mod_rewrite will be enabled by default, but for enhanced security, the default is now for it to be
disabled. Let’s enable the required extension, run:

$ sudo phpenmod mcrypt


$ sudo phpenmod mbstring
$ sudo a2enmod rewrite
$ sudo service apache2 restart
11.5.3 INSTALL COMPOSER GLOBALLY.

The Laravel framework (and most recent PHP packages) use the Composer package management
utility. Composer allows you to quickly and easily install the PHP modules that you need without
having to worry about managing all of their dependencies. Likewise, Composer will automatically
keep all of your packages updated, when maintainers publish new versions.

To simplify use of Composer, we are going to install it globally, so that you can run it from most any
directory in the terminal/shell. (The Laravel installation instructions have you install Composer
specifically for your Laravel project, but that’s usually not necessary.) We won’t go over all of the
details for install Composer, because the Composer web site has simple, yet thorough instructions.
Just go to the Composer Download page and follow the instructions. The only change to make to the
given instructions is that on the third step, run the installer like this:

$ sudo apt-get install composer

11.5.4 CREATE OR PULL YOUR LARAVEL PROJECT IN USER DIRECTORY.

Now we are ready to create our Laravel project, which installs all of the necessary files into a new
directory. For this example, we will create our project in a user directory, which simplifies managing
the permissions of the files and directories. Specifically, we’ll install to projects/laravel_project under
our user’s home directory ($HOME). Here’s how to do it:

$ cd $HOME
$ mkdir projects
$ cd projects
$ composer create-project laravel/laravel laravel_project --prefer-dist
--no-dev 5.3.*

In this example, we are explicitly installing the latest version of Laravel framework 5.3, but you can
choose any version; Also, we use the Composer --prefer-dist parameter to reduce the amount of data
that must be downloaded.

After a few minutes, all of the necessary files will be downloaded and installed, including all of the
dependencies.

11.5.5 SET PERMISSIONS FOR LARAVEL FOLDERS.


Another common pitfall in configuring Laravel on Linux is setting the appropriate permissions for a
couple of the directories. Laravel needs to be able to write transient (temporary) data to some
directories while it’s performing it’s magic, specifically the storage and bootstrap/cache directories.
Run the following commands from the Laravel base project folder (e.g.,
$HOME/projects/laravel_project):

$ chmod -R 777 storage bootstrap/cache

Essentially, this sets “full access” permissions on these directories, so that no matter what process
executes the Laravel application, it will be able to read from and write to them.

11.5.6 SET UP AN APACHE VIRTUAL HOST FOR YOUR LARAVEL PROJECT.

Probably the one thing (from the developer’s perspective anyway!) that Nginx makes so simple
compared to Apache is virtual host configuration. Virtual hosts is the web server terminology for
allowing a single machine (host) to serve multiple web sites. For us, the main value is in allowing us to
create an abbreviated name for our Laravel project. In addition, for Laravel, we actually must use a
virtual host, so that we can properly set permissions for the project directories to avoid ‘403
Forbidden’ HTTP error, due to changes to default security settings in versions 2.4.3 and above of
Apache server. See this article for more details.

In this step, we’ll create a new site configuration named laravel_project.conf which contains our
named virtual host configuration. All of the files that we’ll be working with are system files owned by
the root user, so we must use sudo command with all of them. Also, don’t feel obligated to use the
nano editor; I just use it here, since it’s installed by default on Ubuntu Linux (and it’s a pretty good
editor, too!).

$ sudo cp /etc/apache2/sites-available/000-default.conf
/etc/apache2/sites-available/laravel.conf
$ sudo nano /etc/apache2/sites-available/laravel_project.conf
Modify the laravel_project.conf contents so that they look like this:

NameVirtualHost *:8080
Listen 8080

<VirtualHost *:8080>
ServerAdmin admin@example.com
ServerName laravel.dev
ServerAlias www.laravel.dev
DocumentRoot /home/user/projects/laravel_project/public

<Directory /home/user/projects/laravel_project/public/>
Options Indexes FollowSymLinks MultiViews
AllowOverride All
Order allow,deny
allow from all
Require all granted
</Directory>

LogLevel debug
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
In this file, replace /home/user with the name of the $HOME directory for your account on the
machine. (This is the directory where you created the projects directory earlier.) Also, note that the
root directory (DocumentRoot) is the public directory in your Laravel project folder. This is mainly for
security as it means that the actually application files are stored in directories that the web server
does not have access to. Finally, observe that we have specified that the TCP port that Apache will
allow connections on (“listen” on) for the virtual host is 8080. This is a frequently used alternate port
to the standard HTTP port of 80. We use 8080 to avoid conflicting with any other web applications
already installed on your system.

11.5.7 ADD NEW VIRTUAL HOST TO HOSTS FILE.

You probably noticed in the previous step when setting up the virtual host configuration for our
project, we specified laravel.dev as the ServerName. Basically, this is the “short” name for our virtual
host. So, everything is set from the virtual host perspective to use this name. However, we need to
configure our machine to recognize this name. To do this, we add an entry to machine’s hosts file.
Open the hosts file:

$ sudo nano /etc/hosts

In the hosts file, add this new line at the end (or anywhere):

$ 127.0.0.1 laravel.dev

Save the file.


11.5.8 ENABLE NEW VIRTUAL HOST AND (OPTIONALLY) DISABLE THE DEFAULT VIRTUAL
HOST.

After all of this, we are almost done! The last thing that we need to do is enable the virtual host
configuration laravel_project.conf that we created above. To do this:

$ sudo a2ensite laravel_project.conf

You’ll be prompted to reload the Apache server process. However, before we do that, we (optionally)
may want to disable the default Apache configuration. Again, if you have other web applications, such
as phpMyAdmin, running on your machine, you do not want to disable this configuration. Otherwise,
to avoid confusion, it probably makes sense to disable it:

$ sudo a2dissite 000-default.conf

Note that enabling (a2ensite) and disabling (a2dissite) don’t delete or otherwise change your
configurations; they simply turn them “on” or “off”. (Basically, these utilities create or remove a
symbolic link to the configurations in the /etc/apache2/sites-available directory to the same name in
the /etc/apache2/sites-enabled directory.)

Now, we are ready to restart Apache server and see if everything works! To restart the server:

$ sudo services apache2 restart

Now, open a web browser and enter http://laravel.dev:8080/ in the address field. You should see the
standard Laravel landing page screen.

If you don’t see the landing page, then check that the above steps were performed correctly.
Specifically, ensure that you have set permissions on storage and bootstrap/cache directories and
that you have specified Require all granted in the section of laravel_project.conf.

You might also like