Modul Framework Laravel PDF
Modul Framework Laravel PDF
21 Januari 2019
CONTENTS
Contents ................................................................................................................................................... 2
2 Database ........................................................................................................................................... 7
3 Model ............................................................................................................................................... 9
4 Eloquent ......................................................................................................................................... 36
5 Relationship .................................................................................................................................... 42
2
5.2 One To Many ............................................................................................................ 43
6 Controller .......................................................................................................................................... 9
7 View ................................................................................................................................................ 14
7.1 Layout....................................................................................................................... 20
7.3.4 Troubleshooting................................................................................................... 28
8 Routes ............................................................................................................................................. 14
3
8.5.1 Example ............................................................................................................... 16
9 Security ........................................................................................................................................... 63
9.1 Signup....................................................................................................................... 66
10 Advance ..................................................................................................................................... 93
10.2 Ajax........................................................................................................................... 94
4
1. CREATE LARAVEL PROJECT
Now if you check the file and folder structure of the application (laravel version 5.3), it will look like
(Figure 1):
5
resources/, is a folder to put views of application.
config/, is a folder to setup connection to database, email, global rule app, auth.
.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.
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
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:
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:
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
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
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;
10
3.2.1.2. ADD NEW ARTICLE
Description:
11
3.2.1.3. SHOW ARTICLE DATA
Description:
$request->all(), to get all inputted data. update(), used to change values in database.
12
3.2.1.5. DELETE DATA ARTICLE
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:
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:
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.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.1. EXAMPLE
"Only" & "Except used for register a specific route from resources type routes.
Route::resource('/articles', 'ArticlesController',
['only'=>['index']]);
15
Example for "except":
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::resource('articles', 'ArticlesController');
});
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::get('user/profile', function () {
// Uses Auth Middleware
});
});
4.7.1. EXAMPLE
Namespace use for grouping controller that usually related with role of a user, example:
Route::resource('articles', 'ArticlesController');
});
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.
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:
After that we will setup shared view, create file head_nav.blade.php and left_nav.blade.php at
views/shared/ folder.
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>
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:
$.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;
}
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' => [
composer dumpautoload
-- 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.
@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:
25
5.3.1. SETUP VIEW FOR CREATE DATA
@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:
<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:
@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:
Form::model, is used to declare open form tag, but the Form::model is used for populating data
from controller automatically.
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:
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
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:
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');
}
}
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
Asides from creating we can also manipulate tables, for example is to add and drop column. Create a
migration file:
31
Or another example we can rename column. Create a migration file:
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:
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
Eloquent:
Implementation example:
Article::create($request->all());
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');
Eloquent:
<model_name>::find(<id>);
Implementation example:
Article::find(1);
Eloquent:
<model_name>::where('<column_name>', '<values_for_compare>');
Implementation example:
Eloquent:
DB::table('<table_name_one>')->join('<table_name_two>', '<parent_id>',
'=', '<foreign_id>')->get();
Implementation example:
37
7.4. EDIT A DATA
Eloquent:
$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);
Eloquent:
<model_name>::destroy(<id>);
Implementation example:
Article::destroy([1, 3, 5]);
Eloquent:
<model_name>::where(<your_condition>)->delete();
Implementation example:
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]);
});
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
One to one relationship is when a record in a table is exactly connect to one record in other table.
Parent Model:
Child Model:
8.1.1. EXAMPLE:
Model Husband.php:
42
Model Wive.php:
$husband = Wive::find(1)->husband;
One to Many relationship is when a record in a table can be reference as many on another table.
Parent Model:
Child Model:
43
8.2.1. EXAMPLE
Model Article.php:
$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:
8.3.1. EXAMPLE
45
Model Doctor.php:
$patients = Doctor::find(1)->patients;
8.4. IMPLEMENTATION
Here we will be using One to Many relationship, lets create new model:
return array(
);
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:
After model we need to setup routes, open file routes/web.php and add:
Route::resource('comments', '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:
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
Schema::dropIfExists(‘roles’);
$table->increments(‘id’);
$table->integer(‘role_id’)->unsigned();
$table->integer(‘user_id’)->unsigned();
});
Schema::dropIfExists(‘role_user’);
return $this->belongsToMany(Role::class);
return $this->belongsToMany(User::class);
5. It’s time to create some seeders to add roles and users in the database:
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()
use Illuminate\Database\Seeder;
use App\User;
use App\Role;
class UserTableSeeder extends Seeder
Edit DatabaseSeeder class (database/seeds/ folder) adding the following code in run() method:
/**
* @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)
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.
$this->middleware('auth');
$request->user()->authorizeRoles(['employee',
'manager']);
return view(‘home’);
/*
public function someAdminStuff(Request $request)
$request->user()->authorizeRoles('manager');
return view(‘some.view’);
*/
9.2 ADVANCE
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' =>
Open AdminController.php. Below code in constructor method will check if the logged in user has role
manager role associated with it.
$this->middleware('auth');
$this->middleware('role:manager');
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.
$this->middleware('auth');
$this->middleware('role:manager, employee');
'admin\ManagerController');
});
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
namespace App\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Notifications\Messages\MailMessage;
use Queueable;
public $token;
/**
Create a new notification instance.
@return void
*/
public function construct($token)
$this->token = $token;
/**
Get the notification's delivery channels.
return ['mail'];
/**
Get the mail representation of the notification.
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));
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:
/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.
"require": {
.....
"cartalyst/sentinel": "2.0.*"
},
composer update
After that, we need to add providers & aliases at config/app.php file, first setup providers:
Cartalyst\Sentinel\Laravel\SentinelServiceProvider::class,
Save that file, and make sure our library successfully added. Now terminal run:
composer dumpautoload
Now we will setup migration. To publish migration file run command below:
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:
$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');
});
Schema::drop('users');
}
and change the code into:
$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');
}
$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.
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
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:
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
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
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();
}
}
@extends("layouts.application")
@section("content")
<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>
@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.
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
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
{
return true;
}
public function rules()
{
return [
'email' => 'required',
'password' => 'required'
];
}
The sessions controller that will handle this process, lets create SessionsController, on terminal run:
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');
}
}
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
......
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:
The last step is to setup view, create new file views/sessions/create.blade.php, and add:
@extends("layouts.application")
@section("content")
<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
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:
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:
......
.......
class ReminderMailable extends Mailable
{
use Queueable, SerializesModels;
public $detail;
public function construct($detail)
{
$this->detail = $detail;
}
$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
<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
.....
........
<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:
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:
<?php
namespace App\Http\Controllers;
use App\User;
use App\Http\Requests\ReminderRequest;
use Session, Event;
use Sentinel, Reminder;
use App\Events\ReminderEvent;
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');
}
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.
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class ReminderRequest extends FormRequest
{
public function authorize()
{
return true;
}
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',
],
];
After that we need to generate file Event and Listener base on that mapping, on terminal run:
<?php
........
use Sentinel, Reminder;
use App\User;
class ReminderEvent
{
use InteractsWithSockets, SerializesModels;
public $user;
public $reminder;
<?php
use App\Events\ReminderEvent;
use Mail;
use App\Mail\ReminderMailable;
class ReminderEmailSender
{
public function construct()
......
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:
Open that file that just generated that located at database/seeds/AuthorizeSeeder.php, and add:
<?php
use Illuminate\Database\Seeder;
Sentinel::getRoleRepository()->createModel()->fill($role_admin)-
>save();
$adminrole = Sentinel::findRoleByName('Admin');
$adminuser = Sentinel::registerAndActivate($user_admin);
$adminuser->roles()->attach($adminrole);
Sentinel::getRoleRepository()->createModel()->fill($role_writer)-
>save();
$writerrole = Sentinel::findRoleByName('Writer');
$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:
Middleware used for handle everything that related with authentication or authorization, on terminal
run:
<?php
namespace App\Http\Middleware;
use Closure;
class RoleSentinelMiddleware
{
return $next($request);
} elseif(Sentinel::getUser()->hasAccess('admin')) {
return $next($request);
} else {
return redirect()->route('root');
}
}
}
Description:
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:
....
{
public function construct() {
$this->middleware('sentinel');
$this->middleware('sentinel.role');
....
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);
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.
<!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">
<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 <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>
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:
@extends("layouts.application")
@section("content")
<div id="articles-list">
@include('articles.list')
</div>
@stop
<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>
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:
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.
<?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
*/
$this->call('PUT', 'articles/'.$article->first()->id,
$update_data);
$this->assertRedirectedTo('articles/'.$article->first()-
>id.'/edit');
}
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:
phpunit
.........
OK (9 tests, 17 assertions)
Complete Resources:
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:
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>
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=<database_name>
DB_USERNAME=<user_name>
DB_PASSWORD=<password>
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:
"ellipsesynergie/api-response": "^0.12.3",
EllipseSynergie\ApiResponse\Laravel\ResponseServiceProvider::class,
Composer update
11.4.6 CREATE CONTROLLER, ROUTE, AND TRANSFORMER
<?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;
if($task->delete()) {
return $this->response->withItem($task, new
TaskTransformer());
} else {
return $this->response->errorInternalError('Could not
delete a 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.
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.
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:
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:
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.
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.
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 [email protected]
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.
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:
In the hosts file, add this new line at the end (or anywhere):
$ 127.0.0.1 laravel.dev
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:
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:
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:
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.