Laravel 5 Post PDF
Laravel 5 Post PDF
Laravel 5 Post PDF
Nathan Wu
2015 - 2016 Nathan Wu
Contents
Book Information . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Book Description . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Requirements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
What You Will Get . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Book Structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Chapter 1 - Installing Laravel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Chapter 2 - Building Our First Website . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Chapter 3 - Building A Support Ticket System . . . . . . . . . . . . . . . . . . . . . . 3
Chapter 4 - Building A Blog Application . . . . . . . . . . . . . . . . . . . . . . . . . 3
Chapter 5 - Deploying Our Laravel Applications . . . . . . . . . . . . . . . . . . . . . 3
Feedback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Translation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Book Status, Changelog and Contributors . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Changelog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Current Version . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
Learning Laravel 5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Chapter 1: Installing Laravel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Introducing CLI (Command Line Interface) . . . . . . . . . . . . . . . . . . . . . . . . . 7
CLI for MAC OSX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
CLI for Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
CLI for Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
Installing Laravel Using Homestead . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
What is Homestead? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
How to install Homestead? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Install Homestead Using Method 1 (required Composer) . . . . . . . . . . . . . . . . . 9
Install Homestead Using Method 2 (requires Git) . . . . . . . . . . . . . . . . . . . . . 19
Configure Homestead . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Launching Homestead . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
Installing Laravel . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
CONTENTS
1
Book Description
Learning Laravel 5: Building Practical Applications is the easiest way to learn web development
using Laravel. Throughout 5 chapters, instructor Nathan Wu will teach you how to build many real-
world applications from scratch. This bestseller is also completely about you. It has been structured
very carefully, teaching you all you need to know from installing your Laravel 5 app to deploying
it to a live server.
When you have completed this book you will have created a dynamic website and have a good
knowledge to become a good web developer.
We first start with the basics. You will learn some main concepts and create a simple website. After
that we progress to building more advanced web applications.
Learn by doing!
If youre looking for a genuinely effective book that helps you to build your next amazing
applications, this is the number one book for you.
Requirements
The projects in this book are intended to help people who have grasped the basics of PHP and
HTML to move forward, developing more complex projects, using Laravel advanced techniques.
The fundamentals of the PHP are not covered, you will need to:
2
Book Description 3
Book Structure
Note: This book is still under active development, that means some chapters and its content may
change. The book also may have some errors and bugs. For any feedback, please send us an email.
Thank you.
Feedback
Feedback from our readers is always welcome. Let us know what you liked or may have disliked.
Simply send an email to support@learninglaravel.net.
Were always here.
Translation
Were also looking for translators who can help to translate our book to other languages.
Feel free to contact us at support@learninglaravel.net.
Here is a list of our current translators:
List of Translators
Version: 1.5
Status: Complete. The book now supports Laravel 5.2.
Updated: May 15th, 2016
5
Learning Laravel 5
6
Chapter 1: Installing Laravel
There are many ways to install Laravel. We can install Laravel directly on our main machine, or we
can use all-in-one server stacks such as MAMP, XAMPP, etc. We have a huge selection of ways to
choose.
In this book, I will show you the most popular one: Laravel Homestead.
Working with Laravel requires a lot of interactions with the CLI, thus you will need to know how
to use it.
7
Chapter 1: Installing Laravel 8
What is Homestead?
Nowadays, many developers are using a virtual machine (VM) to develop dynamic websites and
applications. You can run a web server, a database server and all your scripts on that virtual machine.
You can create many VM instances and work on various projects. If you dont want any VM anymore,
you can safely delete it without affecting anything. You can even re-create the VM in minutes!
We call this: Virtualization.
There are many options for virtualization, but the most popular one is VirtualBox from Oracle.
VirtualBox will help us to install and run many virtual machines as we like on our Windows, Mac,
Linux or Solaris operating systems. After that, we will use a tool called Vagrant to manage and
configure our virtual development environments.
In 2014, Taylor Otwell - the creator of Laravel - has introduced Homestead.
Homestead is a Vagrant based Virtual Machine (VM) and it is based on Ubuntu. It includes everything
we need to start developing Laravel applications. That means, when we install Homestead, we have
a virtual server that has PHP, Nginx, databases and other packages. We can start creating our Laravel
application right away.
Here is a list of included software:
Ubuntu 14.04
PHP 5.6
HHVM
Nginx
MySQL
Postgres
Node (With Bower, Grunt, and Gulp)
Redis
Memcached
Beanstalkd
Laravel Envoy
Fabric + HipChat Extension
In May 2015, the Laravel official documentation has been updated. The recommended way to install
Homestead is using Git.
Its better, faster.
Definitely.
However, you can still choose the old way if you like.
Installing VirtualBox
Installing Vagrant
If you still dont know how to install, there is an official guide on Vagrant website:
http://docs.vagrantup.com/v2/installation
What is Composer? Composer is a cross-platform dependency manager for PHP libraries. We use
Composer to install, remove and update PHP packages. You will learn more about it in this book.
For now, we need to install Composer and use it to install Homestead.
For Mac Users
You can find the official installation guide here:
https://getcomposer.org/doc/00-intro.md#installation-linux-unix-osx
To install Composer, we have to use Terminal app, or any other terminal emulator applications (such
as iTerms). On Mac, you can find it at Applications-> Utilities-> Terminal.
Most of what you do in the Terminal app is enter specific text strings, then press Return to execute
them.
Lets install Composer by executing this command:
Chapter 1: Installing Laravel 12
The installer will download composer.phar to your working directory. To access composer easily
from anywhere on our system, we need to move the composer.phar file to /usr/local/bin directory.
Execute this command:
Note: In OSX Yosemite, there is no /usr directory by default. If you see this error:
then you must create /usr/local/bin manually by entering this command first:
Chap1 Pic 1
Chap1 Pic 1
*Note: If you have multiple VM apps (such as VMware of Parallels), make sure to choose
VirtualBox:
Chapter 1: Installing Laravel 16
Downloading Homestead
Youre now ready to install Homestead using Composer, enter this command:
homestead init
Note: If youre seeing this error: command not found: homestead. You need to
configure your $PATH. Please check out this guide to understand what $PATH is and
how to edit it:
http://www.cyberciti.biz/faq/appleosx-bash-unix-change-set-path-environment-variable
Basically, you will need to add this line to your $PATH variable by editing .bash_profile
file or .zshrc file (if youre using zsh)
Chapter 1: Installing Laravel 17
export PATH=~/.composer/vendor/bin/:$PATH
If you can run the homestead init command successfully, you may edit the Homestead.yaml file
by using homestead edit command:
homestead edit
Alternatively, you can find the Homestead.yaml in the /.homestead directory (the directory
is hidden by default, make sure that you can see hidden files if you want to find it). Open the
Homestead.yaml file with a text editor to edit it.
Chapter 1: Installing Laravel 19
Installing VirtualBox
Chapter 1: Installing Laravel 20
Installing Vagrant
If you still dont know how to install, there is an official guide on Vagrant website:
http://docs.vagrantup.com/v2/installation
Note: if you dont know how to run a command, please read Introducing CLI
(Command Line Interface) section.
Chapter 1: Installing Laravel 21
xcode-select --install
For more information and other methods, you can see this guide:
https://git-scm.com/book/en/v2/Getting-Started-Installing-Git
When you have Git installed. Enter the following command to your Terminal (or Git Bash):
Cloning Homestead
cd Homestead
bash init.sh
The Homestead.yaml file will be placed in your /.homestead directory. Open it with a text editor
to edit it.
Please note that the /.homestead directory is hidden by default, make sure that you
can see hidden files.
Chapter 1: Installing Laravel 23
If you know how to use VI or VIM, use this command to edit the file:
vi ~/.homestead/Homestead.yaml
Configure Homestead
The structure of the Homestead.yaml is simple. There are 7 sections. Lets see what they do.
ip: "192.168.10.10"
memory: 2048
cpus: 1
provider: virtualbox
As you can see, we can configure the IP address, memory, cpus and provider of our VM. This section
is not important, so we can just leave it as it is.
authorize: ~/.ssh/id_rsa.pub
keys:
- ~/.ssh/id_rsa
Basically, we need to generate an SSH key for Homestead to authenticate the user and connect to
the VM. If youre working with Git, you may have an SSH key already. If you dont have it, simply
run this command to generate it:
The command will generate an SSH key for you and put it in the /.ssh directory automatically,
you dont need to do anything else.
We use folders section to specify the directory that we want to share with our Homestead
environment. If we add, edit or change any files on our local machine, the files will be updated
automatically on our Homestead VM.
folders:
- map: ~/Code
to: /home/vagrant/Code
We can see that the /Code directory has been put there by default. This is where we put all the files,
scripts on our local machine. Feel free to change the link if you want to put your codes elsewhere.
The /home/vagrant/Code is a path to the Code directory on our VM. Usually, we dont need to
change it.
sites:
- map: homestead.app
to: /home/vagrant/Code/Laravel/public
This section allows us to map a domain to a folder on our VM. For example, we can map
homestead.app to the public folder of our Laravel project, and then we can easily access our Laravel
app via this address: http://homestead.app.
Remember that, when we add any domain, we must edit the hosts file on our local machine to
redirect requests to our Homestead environment.
On Linux or Mac, you can find the hosts file at etc/hosts or /private/etc/hosts. You can edit the
hosts file using this command:
If you know how to use VI or VIM, use this command to edit the file:
192.168.10.10 homestead.app
Done! When we launch Homestead, we can access the site via this address.
http://homestead.app
Please note that we can change the address (homestead.app) to whatever we like.
All sites will be accessible by HTTP via port 8000 and HTTPS via port 44300 by default.
databases:
- homestead
This is the database name of our VM. As usual, we just leave it as it is.
variables:
- key: APP_ENV
value: local
If we want to add some custom variables to our VM, we can add them here. Its not important, so
lets move to the next fun part.
Launching Homestead
Once we have edited Homestead.yaml file, cd to the Homestead directory, run this command to
boot our virtual machine:
vagrant up
Homestead error
It means that you dont have Code directory in your main machine. You can create one, or change
the link to any folder that you like.
Executing this command to create Code folder:
Note: if you have any errors when creating Laravel, try to set right permissions for the
Code folder by running:
Booting Homestead
vagrant ssh
SSH Homestead
Run ls command
If you can see the Code directory there, you have Homestead installed correctly!
Excellent! Lets start installing Laravel!
Installing Laravel
When you have installed Homestead, create a new Laravel app is so easy!
As Ive mentioned before, the Code directory is where we will put our Laravel apps. Lets go there!
cd Code
You should notice that the directory is empty. There are two methods to install Laravel.
Chapter 1: Installing Laravel 28
This method is recommended. Its newer and faster. You should use this method to create your
Laravel application.
First, we need to use Composer to download the Laravel installer.
This command is used to download Laravel 5.0, if you want to use the latest version, use:
Note: It is recommended to use Laravel 5.0 to learn the basics of Laravel Framework.
You can upgrade to a newer version later. However, feel free to use the latest version if
you want because the book will be updated frequently to support newer versions.
Once downloaded, you can create a new Laravel project by using this command:
Youre free to change the nameOfYourSite to whatever you like, but remember to edit the sites
section of Homestead.yaml to match your sites name.
For instance, in Homestead.yaml, we specify the name of our app is Laravel
Chapter 1: Installing Laravel 29
sites:
- map: homestead.app
to: /home/vagrant/Code/Laravel/public
Laravel is ready!
If you dont like to use Laravel Installer, or you have any problems with it, feel free to use Composer
Create-Project to create a new Laravel app.
This command is used to download Laravel 5.0, if you want to use the latest version, use:
Youre free to change the nameOfYourSite to whatever you like, but remember to edit the sites
section of Homestead.yaml to match your sites name.
For instance, in Homestead.yaml, we specify the name of our app is Laravel
Chapter 1: Installing Laravel 31
sites:
- map: homestead.app
to: /home/vagrant/Code/Laravel/public
Alternatively, we can create a new Laravel folder, cd to it, and create our Laravel app there:
mkdir Laravel
cd Laravel
composer create-project laravel/laravel --prefer-dist
Laravel is ready!
Note: if you cannot access the site, try to add the port into the URL: http://homestead.app:8000.
Congratulations! Youve installed Laravel! Its time to create something amazing!
Chapter 2: Building Our First Website
Now that we know how to install Laravel, lets start working our way into our first Laravel website.
In this chapter, you will learn about Laravel structure, routes, Controllers, Blade templates, Artisan
commands, Elixir and many basic features that will come handy when building Laravel applications.
Laravel structure
To build applications using Laravel, you will need to understand truly Laravel.
Laravel follows MVC (Model View Controller) pattern, so if youve already known about MVC,
everything will be simple. Dont worry if you dont know what MVC is, you will get to know soon.
As you may have seen, every time you visit a Laravel app, youll see nine folders.
1. app
33
Chapter 2: Building Our First Website 34
2. bootstrap
3. config
4. database
5. public
6. resources
7. storage
8. tests
9. vendor
Im not going to tell you everything about them right now because I know that its boring.
Trust me.
But we have to take a quick look at them to know what they are, anyway.
App
This directory holds all our applications logic. We will put our controllers, services, filters,
commands and many other custom classes here.
#### Bootstrap
This folder has some files that are used to bootstrap Laravel. The cache folder is also placed here.
Config
When we want to configure our application, check out this folder. We will configure database, mail,
session, etc. here.
Database
As the name implies, this folder contains our database migrations and database seeders.
Public
The public folder contains the applications images, CSS, JS and other public files.
Resources
We should put our views (.blade.php files), raw files and other localization files here.
Storage
Laravel will use this folder to store sessions, caches, templates, logs, etc.
Chapter 2: Building Our First Website 35
Tests
Vendor
Composer dependencies (such as Symfony classes, PHPUnit classes, etc.) are placed here.
To understand more about Laravel structure, you can read the official documentation here:
http://laravel.com/docs/master/structure
Understand routes.php
One of the most important files of Laravel is routes.php. This file can be found at Laravel/app/Http/.
We use this file for routing.
What does it mean?
Routing means that you will tell Laravel to get URL requests and assign them to specific actions
that you want. For instance, when someone visits homestead.app, which is the home page of our
current application, Laravel will think: Oh, this guy is going to the home page, I need to display
the welcome view and then give the guy some quotes to read!
We usually register all routes in the routes.php file.
Route::get('/', function () {
return view('welcome');
});
Note: Since Laravel 5.1, the routes.php file has been changed. If you see a different
routes.php file, you may have an older Laravel version, please upgrade your application
to version 5.1 or newer.
Route::get('/', 'WelcomeController@index');
Route::get('home', 'HomeController@index');
Route::controllers([
'auth' => 'Auth\AuthController',
'password' => 'Auth\PasswordController',
]);
So if we want to edit the home page, we need to modify the welcome view.
What is view and where is the welcome view?
Views contain the HTML served by our application. A simple view may look like a simple HTML
file:
<html>
<body>
<p> A simple view </p>
</body
</html>
<html>
<head>
<title>Laravel</title>
<style>
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
color: #B0BEC5;
display: table;
font-weight: 100;
font-family: 'Lato';
}
Chapter 2: Building Our First Website 37
.container {
text-align: center;
display: table-cell;
vertical-align: middle;
}
.content {
text-align: center;
display: inline-block;
}
.title {
font-size: 96px;
margin-bottom: 40px;
}
.quote {
font-size: 24px;
}
</style>
</head>
<body>
<div class="container">
<div class="content">
<div class="title">Laravel 5</div>
<div class="quote">{{ Inspiring::quote() }}</div>
</div>
</div>
</body>
</html>
This welcome view is used to display the home page. It just looks like a basic HTML file!
I assume that youve already known HTML, so you should understand the content of this file clearly.
If you dont, w3schools is a good place to learn HTML and PHP.
http://www.w3schools.com/html
Its time to modify the home page!
What should we do?
How about display our own quote?
Lets change this line:
Chapter 2: Building Our First Website 38
to
Save the file, head over to your browser and run homestead.app.
Awesome! We have just changed our home page by changing the welcome.blade.php template!
In fact, we can change any page without returning a view:
Modify the first route:
Chapter 2: Building Our First Website 39
Route::get('/', function () {
return view('welcome');
});
to
Route::get('/', function()
{
return 'Welcome to our home page!';
});
Amazing! Right?
We have just used a anonymous function to change our home page. In PHP, we called this function:
Closure.
A Closure is a function that doesnt have a name.
Chapter 2: Building Our First Website 40
We use Closure to handle routing in small applications. In large applications, we use Controllers.
You can find Controllers documentation here:
http://laravel.com/docs/master/controllers
Its recommended that you should always use Controllers because Controllers help to structure your
code easier. For instance, you may group all user actions into UserController, all post actions into
PostsController.
The disadvantage of Controllers is, you will need to create a file for each Controller, thus it takes a
bit more time.
To understand what Controllers is, we will be creating some pages using Controllers.
1. Home page.
2. About page.
3. Contact page.
Because we have many pages, and we might add more pages into our website, we should organize
all our pages in PagesController.
As youve noticed, we dont have the PagesController yet, thus were going to create it.
To start off with things, create a new file called PagesController.php with your favourite text editor
(PHPStorm, Sublime Text, etc.).
Place the file in app/Http/Controllers/ directory.
Update the PagesController.php file to look like this:
Chapter 2: Building Our First Website 41
return view('welcome');
Rather than manually creating a controller, we can use Artisan to generate it automatically.
Artisan is Laravel command line tool that helps us to perform tasks that we hate to do manually.
Using Artisan, we can create models, views, controllers, migrations and many other things.
You have known how to use Terminal or Git Bash, lets create a controller by running this command:
Note: vagrant ssh to your VM, cd to Laravel folder, and use the command there.
Youll see:
By default, Laravel creates a RESTful controller. Therefore, our PagesController class will have
these actions:
Chapter 2: Building Our First Website 42
1. index
2. show
3. create
4. store
5. edit
6. update
7. destroy
We dont need any of these, you can just remove them all and replace them with a home action:
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
Alternatively, you can use this command to generate a new PagesController that doesnt have any
action:
Note: Since Laravel 5.2, the plain flag has been removed. The controllers will always
be plain.
Good job! You now have PagesController with the home action.
You may notice that the home action tells Laravel to return the welcome view:
return view('welcome');
Route::get('/', 'PagesController@home');
This route tells Laravel to execute the home action (which can be found in PagesController) when
someone make a GET request to our root URL (which represents by the /).
Well done! Youve just displayed the front page using your own controller!
How about trying to add the about and contact page yourself?
Route::get('/about', 'PagesController@about');
Route::get('/contact', 'PagesController@contact');
Next you will want to create about view and contact view. Create two new files in the re-
sources/views directory named about.blade.php and contact.blade.php.
Finally, add the following contents (copy from the welcome view) to each file:
about.blade.php
<html>
<head>
<title>About Page</title>
<style>
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
color: #B0BEC5;
display: table;
font-weight: 100;
font-family: 'Lato';
}
.container {
text-align: center;
Chapter 2: Building Our First Website 45
display: table-cell;
vertical-align: middle;
}
.content {
text-align: center;
display: inline-block;
}
.title {
font-size: 96px;
margin-bottom: 40px;
}
.quote {
font-size: 24px;
}
</style>
</head>
<body>
<div class="container">
<div class="content">
<div class="title">About Page</div>
<div class="quote">Our about page!</div>
</div>
</div>
</body>
</html>
contact.blade.php
<html>
<head>
<title>Contact Page</title>
<style>
body {
margin: 0;
padding: 0;
Chapter 2: Building Our First Website 46
width: 100%;
height: 100%;
color: #B0BEC5;
display: table;
font-weight: 100;
font-family: 'Lato';
}
.container {
text-align: center;
display: table-cell;
vertical-align: middle;
}
.content {
text-align: center;
display: inline-block;
}
.title {
font-size: 96px;
margin-bottom: 40px;
}
.quote {
font-size: 24px;
}
</style>
</head>
<body>
<div class="container">
<div class="content">
<div class="title">Contact Page</div>
<div class="quote">Our contact page!</div>
</div>
</div>
</body>
</html>
About page
Chapter 2: Building Our First Website 48
Contact page
Yayyyy! We have created the about and contact page with just a few lines of code!
Now, lets create a home view for our homepage, and change the PagesController to use it:
*Note: if you see the default home.blade.php file, just delete it and create a new file.
home view:
Chapter 2: Building Our First Website 49
<html>
<head>
<title>Home Page</title>
<style>
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
color: #B0BEC5;
display: table;
font-weight: 100;
font-family: 'Lato';
}
.container {
text-align: center;
display: table-cell;
vertical-align: middle;
}
.content {
text-align: center;
display: inline-block;
}
.title {
font-size: 96px;
margin-bottom: 40px;
}
.quote {
font-size: 24px;
}
</style>
</head>
<body>
<div class="container">
Chapter 2: Building Our First Website 50
<div class="content">
<div class="title">Home Page</div>
<div class="quote">Our Home page!</div>
</div>
</div>
</body>
</html>
PagesControllers
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js\
"></script>
Done! You now have fully integrated Twitter Bootstrap into our website!
You may notice that weve added some CSS styles and Lato font into our home.blade.php file before.
Remove those:
<style>
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
color: #B0BEC5;
display: table;
font-weight: 100;
font-family: 'Lato';
}
.container {
text-align: center;
display: table-cell;
vertical-align: middle;
}
.content {
text-align: center;
display: inline-block;
}
.title {
font-size: 96px;
margin-bottom: 40px;
}
.quote {
Chapter 2: Building Our First Website 52
font-size: 24px;
}
</style>
and
<html>
<head>
<title>Home Page</title>
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.mi\
n.js"></script>
</head>
<body>
<div class="container">
<div class="content">
<div class="title">Home Page</div>
<div class="quote">Our Home page!</div>
</div>
</div>
</body>
</html>
Less allows us to use variables, mixins, functions and other techniques to enhance CSS. You can
learn more about Less here:
http://lesscss.org
Unfortunately, browsers dont understand Less. You must compile all Less files using Less compiler
to produce CSS files. Of course, you have to learn Less.
Luckily, Bootstrap has provided compiled CSS, JS and fonts for us. We can download and use them
without worrying about the Less files. Go to:
http://getbootstrap.com/getting-started
Click Download Bootstrap to download latest compiled Bootstrap files.
Uncompress the downloaded .zip file. We have three folders:
1. css
2. js
3. fonts
Put them all into the public folder of your app. (/Code/Laravel/public).
Note: By default, Laravel has created css and fonts folder for us. The fonts folder also
contains all the glyphicons fonts.
When you visit your public folder, it should look like this:
Bootstrap navbar
To load Twitter Bootstrap framework for styling our home page, open home.blade.php and place
these links inside the head tag
Chapter 2: Building Our First Website 54
Twitter Bootstrap requires jQuery to work properly, you can download jQuery here:
https://jquery.com/download
Put the jQuery file into the public directory as well, then use the following code to reference it:
Or you can just use jQuery CDN without downloading the jQuery file:
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
Full code:
Done! You now have fully integrated Twitter Bootstrap into our website!
Weve used asset function to link CSS and JS files to our app. You can also use the asset function to
link images, fonts and other public files. If you dont want to use asset function, you can use relative
links instead:
<script src="/js/jquery-1.11.3.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
You may notice that weve added some CSS styles and Lato font into our home.blade.php file before.
Remove those:
Chapter 2: Building Our First Website 55
<style>
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
color: #B0BEC5;
display: table;
font-weight: 100;
font-family: 'Lato';
}
.container {
text-align: center;
display: table-cell;
vertical-align: middle;
}
.content {
text-align: center;
display: inline-block;
}
.title {
font-size: 96px;
margin-bottom: 40px;
}
.quote {
font-size: 24px;
}
</style>
and
<html>
<head>
<title>Home Page</title>
</head>
<body>
<div class="container">
<div class="content">
<div class="title">Home Page</div>
<div class="quote">Our Home page!</div>
</div>
</div>
</body>
</html>
@import "bootstrap/bootstrap";
Note: Since Laravel 5.1, Laravel has removed Bootstrap Less source files.
Twitter Bootstrap requires jQuery and Twitter Bootstrap JS to work properly, we need to integrate
Bootstrap JS and jQuery:
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js\
"></script>
Alternatively, you can download the js files to the js directory and reference them locally:
Full code:
Done! You now have fully integrated Twitter Bootstrap into your website!
Weve used asset function to link CSS and JS files to our app. You can also use the asset function
to link images, fonts and other public files. If you dont want to use asset function, you can use
relative links instead:
You may notice that weve added some CSS styles and Lato font into our home.blade.php file
before. Remove those:
Chapter 2: Building Our First Website 58
<style>
body {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
color: #B0BEC5;
display: table;
font-weight: 100;
font-family: 'Lato';
}
.container {
text-align: center;
display: table-cell;
vertical-align: middle;
}
.content {
text-align: center;
display: inline-block;
}
.title {
font-size: 96px;
margin-bottom: 40px;
}
.quote {
font-size: 24px;
}
</style>
and
<html>
<head>
<title>Home Page</title>
</head>
<body>
<div class="container">
<div class="content">
<div class="title">Home Page</div>
<div class="quote">Our Home page!</div>
</div>
</div>
</body>
</html>
Introducting Elixir
One of the best Laravel 5 new features is Elixir. We can use Elixir to compile Less files, Coffee Scripts
or automate other manual tasks.
Elixir official documentation
Basically, Elixir is Gulps extension. If you dont know about Gulp yet, you can find more information
about it here:
http://gulpjs.com
Gulp is a Node.js based task runner, that means if you want to use Elixir, you need to have both
Gulp and Node.js installed.
Luckily, Homestead has Gulp and Node.js by default, we can use Gulp right away. If you dont use
Homestead, you have to install Node.js and Gulp. To install Node.js, visit:
https://nodejs.org
Follow instructions on the site, you should have installed Node.js easily. After that, you can use npm
command to install gulp:
gulp -v
The last step is to install Elixir. Laravel 5 has included a file called package.json. You use this file to
install Node modules. Open the file, you should see:
{
"private": true,
"devDependencies": {
"gulp": "^3.8.8",
"laravel-elixir": "^1.0.0"
}
}
npm install
Installing Elixir
You can write Gulp task (or Elixir task) in gulpfile.js. For instance, you can find a Gulp task that
compiles app.less file into app.css in the gulpfile.js:
Chapter 2: Building Our First Website 61
elixir(function(mix) {
mix.less('app.less');
});
Feel free to add more tasks by reading the official Elixir documentation:
http://laravel.com/docs/master/elixir
To execute your Elixir tasks, run this command:
gulp
By running the task, Laravel will automatically compile app.less and save the output to app.css. The
file can be found in your public/css directory.
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Link <span class="sr-only">(current)</spa\
n></a></li>
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="butto\
n" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li class="divider"></li>
<li><a href="#">Separated link</a></li>
<li class="divider"></li>
<li><a href="#">One more separated link</a></li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-left" role="search">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Link</a></li>
Chapter 2: Building Our First Website 63
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="butto\
n" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li class="divider"></li>
<li><a href="#">Separated link</a></li>
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<html>
<head>
<title>Home Page</title>
</head>
<body>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">Brand</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Link <span class="sr-only">(curre\
nt)</span></a></li>
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" r\
ole="button" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li class="divider"></li>
<li><a href="#">Separated link</a></li>
<li class="divider"></li>
<li><a href="#">One more separated link</a></li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-left" role="search">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" r\
ole="button" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li class="divider"></li>
<li><a href="#">Separated link</a></li>
Chapter 2: Building Our First Website 65
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<div class="container">
<div class="content">
<div class="title">Home Page</div>
<div class="quote">Our Home page!</div>
</div>
</div>
</body>
</html>
Bootstrap navbar
@if ($product == 1)
{!! $product->name !!}
@else
There is no product!
@endif
if ($product ==1) {
echo $product->name;
} else {
echo("There is no product!");
}
To understand Blades features, we will use Blade to build our first websites layout.
<html>
<head>
<title> @yield('title') </title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4\
/css/bootstrap.min.css">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4\
/css/bootstrap-theme.min.css">
<script src="//code.jquery.com/jquery-1.11.3.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.mi\
n.js"></script>
</head>
<body>
@include('shared.navbar')
@yield('content')
</body>
</html>
Chapter 2: Building Our First Website 68
This view look likes the home view, but weve changed something. Lets see the code line by line.
Instead of putting a title here, we use @yield directive to get the title from another section.
@include('shared.navbar')
We use @include directive to include other Blade views. You may notice that weve embed a view
called navbar here.
However, we dont have the navbar view yet, lets create a shared directory and put navbar.blade.php
there.
Copy the Twitter Bootstrap navbar and put it into the navbar.blade.php:
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="#">Link <span class="sr-only">(curre\
nt)</span></a></li>
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" r\
ole="button" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
Chapter 2: Building Our First Website 69
<li class="divider"></li>
<li><a href="#">Separated link</a></li>
<li class="divider"></li>
<li><a href="#">One more separated link</a></li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-left" role="search">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" r\
ole="button" aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li class="divider"></li>
<li><a href="#">Separated link</a></li>
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
You may change the shared folder name to partials, embed or whatever you like.
@yield('content')
As you see its really convenient for us to not display the content of any pages here. We simply use
@yield directive to embed a section called content from other views.
Great! Youve just created a master layout!
@extends('master')
@section('title', 'Home')
@section('content')
<div class="container">
<div class="content">
<div class="title">Home Page</div>
<div class="quote">Our Home page!</div>
</div>
</div>
@endsection
As you can observe we use @extends directive to inherit our master layout.
To set the title for our home page, we use @section directive.
@section('title', 'Home')
Its the short way. If we have a long content, we can use @section and @endsection to inject
our content into the master layout.
@section('content')
<div class="container">
<div class="content">
<div class="title">Home Page</div>
<div class="quote">Our Home page!</div>
</div>
</div>
@endsection
Refresh your browser, you should see the same home page, but this time our code look much cleaner.
Chapter 2: Building Our First Website 71
Using the same technique, we can easily change the about and contact page:
about.blade.php
@extends('master')
@section('title', 'About')
@section('content')
<div class="container">
<div class="content">
<div class="title">About Page</div>
<div class="quote">Our about page!</div>
</div>
</div>
@endsection
contact.blade.php
Chapter 2: Building Our First Website 72
@extends('master')
@section('title', 'Contact')
@section('content')
<div class="container">
<div class="content">
<div class="title">Contact Page</div>
<div class="quote">Our contact page!</div>
</div>
</div>
@endsection
1. http://bootswatch.com
2. http://fezvrasta.github.io/bootstrap-material-design
3. http://designmodo.github.io/Flat-UI
In this section, were going to apply Bootstrap Material Design theme for our website.
This Bootstrap theme will provide an easy way to use the new Material Design guidelines by
Google. If youre using an Android phone, you may have seen Material Design already. You can
find out more about Material Design here:
http://www.google.com/design/spec/material-design/introduction.html
This section is designed to test your knowledge of the Laravel 5 structure and views. Ill additionally
show you how to manage your assets. Feel free to use other themes if you want. We also build a
good template to use for all applications of this book.
First, head over to:
https://github.com/FezVrasta/bootstrap-material-design
Download the zip file. Uncompressed it. Go to the dist directory. There are 3 folders:
1. css
2. js
3. fonts
Copy css, fonts, and js directory to our Laravel public folder. (/Code/Laravel/public).
Open master.blade.php, modify its content to look like this:
Chapter 2: Building Our First Website 74
<html>
<head>
<title> @yield('title') </title>
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css"\
rel="stylesheet">
<!-- Include roboto.css to use the Roboto web font, material.css to include \
the theme and ripples.css to style the ripple effect -->
<link href="/css/roboto.min.css" rel="stylesheet">
<link href="/css/material.min.css" rel="stylesheet">
<link href="/css/ripples.min.css" rel="stylesheet">
</head>
<body>
@include('shared.navbar')
@yield('content')
<script src="//code.jquery.com/jquery-1.10.2.min.js"></script>
<script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></sc\
ript>
<script src="/js/ripples.min.js"></script>
<script src="/js/material.min.js"></script>
<script>
$(document).ready(function() {
// This command is used to initialize some elements and make them work p\
roperly
$.material.init();
});
</script>
</body>
</html>
A new navbar
@extends('master')
@section('title', 'Home')
@section('content')
<div class="container">
<div class="row banner">
<div class="col-md-12">
Chapter 2: Building Our First Website 78
<div class="text-center">
<img src="http://learninglaravel.net/img/LearningLaravel5_co\
ver0.png" width="302" height="391" alt="">
</div>
</div>
</div>
</div>
@endsection
Chapter 2: Building Our First Website 79
Responsive website
You may try to navigate to the about and contact page to see if everything is working correctly.
Feel free to change minor things like images, contents, colors, and fonts to your liking.
Chapter 2: Building Our First Website 81
Chapter 2 Summary
Good job! We now have a fully responsive template! We will use this template to build other
applications to learn more about Laravel.
In this chapter, youve learned many things:
1. Youve known about Laravel structure, how Laravel works and where to put the files.
2. Youve learned about Laravel routes.
3. Youve learned Controllers. Now you can be able to create web pages using Controllers.
4. Youve known what Blade is. Its easy to create Blade templates for your next amazing
applications.
5. Youve known how to integrate Twitter Bootstrap, CSS, JS and apply different Bootstrap
themes.
6. Youve known Elixir, how to install Gulp, and how to create a basic Gulp task.
In the next chapter, we will learn how to create a basic CRUD (Create, Read, Update, Delete)
application to learn more about Laravels features.
Chapter 3: Building A Support Ticket
System
In this chapter, we will build a support ticket system to learn about Laravel main features, such as
Eloquent ORM, Eloquent Relationships, Migrations, Requests, Laravel Collective, sending emails,
etc.
While the project design is simple, it provides an excellent way to learn Laravel.
When users visit the contact page, they will be able to submit a ticket to contact us.
Once theyve created a ticket, the system will send us an email to let us know that there is a
new ticket.
The ticket system automatically generates a unique link to let us access the ticket.
We can view all the tickets.
We can be able to reply, edit, change tickets status or delete them.
1. MySQL
82
Chapter 3: Building A Support Ticket System 83
2. SQLite
3. PostgreSQL
4. SQL Server
Note: A database is a collection of data. We use database to store, manage and update
our data easier.
The great thing is, we can choose any of them to develop our applications. In this book, we will use
MySQL.
You can configure databases using database.php file, which is placed in the config directory.
config/database.php
<?php
return [
/*
|--------------------------------------------------------------------------
| PDO Fetch Style
|--------------------------------------------------------------------------
|
| By default, database results will be returned as instances of the PHP
| stdClass object; however, you may desire to retrieve records in an
| array format for simplicity. Here you can tweak the fetch style.
|
*/
/*
|--------------------------------------------------------------------------
| Default Database Connection Name
|--------------------------------------------------------------------------
|
| Here you may specify which of the database connections below you wish
| to use as your default connection for all database work. Of course
| you may use many connections at once using the Database library.
|
*/
/*
|--------------------------------------------------------------------------
| Database Connections
|--------------------------------------------------------------------------
|
| Here are each of the database connections setup for your application.
| Of course, examples of configuring each database platform that is
| supported by Laravel is shown below to make development simple.
|
|
| All database work in Laravel is done through the PHP PDO facilities
| so make sure you have the driver for your particular database of
| choice installed on your machine before you begin development.
|
*/
'connections' => [
'sqlite' => [
'driver' => 'sqlite',
'database' => storage_path('database.sqlite'),
'prefix' => '',
],
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', 'localhost'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'charset' => 'utf8',
'collation' => 'utf8_unicode_ci',
'prefix' => '',
'strict' => false,
],
'pgsql' => [
'driver' => 'pgsql',
'host' => env('DB_HOST', 'localhost'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
Chapter 3: Building A Support Ticket System 85
'sqlsrv' => [
'driver' => 'sqlsrv',
'host' => env('DB_HOST', 'localhost'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'prefix' => '',
],
],
/*
|--------------------------------------------------------------------------
| Migration Repository Table
|--------------------------------------------------------------------------
|
| This table keeps track of all the migrations that have already run for
| your application. Using this information, we can determine which of
| the migrations on disk haven't actually been run in the database.
|
*/
/*
|--------------------------------------------------------------------------
| Redis Databases
|--------------------------------------------------------------------------
|
| Redis is an open source, fast, and advanced key-value store that also
| provides a richer set of commands than a typical key-value systems
| such as APC or Memcached. Laravel makes it easy to dig right in.
|
*/
'redis' => [
Chapter 3: Building A Support Ticket System 86
'default' => [
'host' => '127.0.0.1',
'port' => 6379,
'database' => 0,
],
],
];
Try to read the comments to understand how to use this file. The most two important settings are:
1. default: You can set the type of database you would like to use here. By default, it is mysql. If
you want to use a different database, you can set it to: pgsql, sqlite, sqlsrv.
2. connections: Fill your database authentication credentials here. The env() function is
used to retrieve configuration variables (DB_HOST, DB_DATABASE, DB_USERNAME,
DB_PASSWORD) from .env file. If it cant find any variables, it will use the value of the
functions second parameter (localhost, forge).
If you use Homestead, Laravel has created a homestead database for you already. If you dont use
Homestead, you will need to create a database manually.
Laravel uses PHP Data Objects (PDO). When we execute a Laravel SQL query, rows are returned in
a form of a stdClass object. For instance, we may access our data using:
$user->name
You can easily change the fetch style to return result in array format by editing this line:
update to:
Create a database
Note: You need a basic understanding of SQL to develop Laravel applications. At
least, you should know how to read, update, modify and delete a database and
its tables. If you dont know anything about database, a good place to learn is:
http://www.w3schools.com/sql
To develop multiple applications, we will need multiple databases. In this section, we will learn how
to create a database.
mysql -uhomestead -p
show databases
exit
Even though we can easily create a new database via the CLI, we should use a Graphical User
Interface (GUI) to manage databases easily.
Once connected, you can easily create a new database by clicking Choose Database and then Add
Database.
Alternatively, you may use Navicat.
Chapter 3: Building A Support Ticket System 89
Using Migrations
One of the best features of Laravel is Migrations.
Whether youre working with a team or alone, you may need to find a way to keep track your
database schema. Laravel Migrations is the right way to go.
Laravel uses migration files to know what we change in our database. The great thing is, you can
easily revert or apply changes to your applications by just running a command. For example, we
can use this command to reset the database:
Its easy?
This feature is very useful. You should always use Migrations to build your applications database
schema.
You can find Migrations documentation at:
http://laravel.com/docs/master/migrations
Youll see:
Laravel will create a new migration template and place it in your database/migrations directory.
The name of the new migration template is: create_tickets_table. You can name it whatever you
want. Check the migrations directory, youll find a file look like this:
2015_06_15_150120_create_tickets_table.php
You may notice that Laravel put a timestamp before the name of the file, it helps to determine the
order of the migrations.
Open the file:
Chapter 3: Building A Support Ticket System 91
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
//
}
}
Basically, a migration is just a standard class. There are two important methods:
1. up method: you use this method to add new tables, column to the database.
2. down method: well, you might have guessed already, this method is used to reverse what
youve created.
By using the create option, Laravel automatically generates the codes to create the tickets table for
you.
Schema::create method has two parameters. The first one is the name of the table.
The second one is a Closure. The Closure has one parameter: $table. You can name the parameter
whatever you like.
We use the $table parameter to create database columns, such as id, name, date, etc.
$table->increments('id');
$table->timestamps();
id
title
content
slug: URL friendly version of the ticket title
status: current status of the ticket (answered or pending)
user_id: who created the ticket
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
Chapter 3: Building A Support Ticket System 94
{
Schema::drop('tickets');
}
}
Finally, run this command to create the tickets table and its columns:
The first time you run this command, Laravel will create a migration table to keep track of what
migrations youve created.
By default, Laravel also creates create_users_table migration and create_password_resets migra-
tion for us. These migrations will create users and password_resets tables. If you want to implement
the default authentication, leave the files there. Otherwise, you can just delete them, or run php
artisan fresh command to completely remove the default authentication feature.
Well, I guess it worked! It looks like the tables have been created. Lets check the homestead
database:
Chapter 3: Building A Support Ticket System 95
Note: I use the homestead database. If you like to use another one, feel free to change
it using the .env file.
Well done! Youve just created a new tickets table to store our data.
home screen. But no matter you customize it, its still based on the blueprint that was created by the
manufacturer.
We call that blueprint: model. Basically, models just a class. Each model has its own variables
(features of each mobile phone) and methods (actions that you take to customize the phone).
Model is known as the M in the MVC system (Model-View-Controller).
Now lets get back to our tickets table. If we can turn the tickets table to be a model, we can then
easily access and manage it. Eloquent helps us to do the magic.
We may use Eloquent ORM to create, edit, manipulate, deletes our tickets without writing a single
line of SQL!
To get started, lets create our first Ticket model by running this Artisan command:
Note: a model name should be singular, and a table name should be plural.
Cool?
Ok, lets open our new Ticket model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
As you may notice, the Ticket model is just a PHP class that extends the Model class. Now we can
use this file to tell Laravel about its relationships. For instance, each ticket is created by a user, we
can tell tickets belongs to users by writing like this:
Chapter 3: Building A Support Ticket System 97
We also can be able to use this model to access any tickets data, such as: title, content, etc.
Eloquent is clever. It automatically finds and connects our models with our database tables if you
name them correctly (Ticket model and tickets table, in this case).
For some reasons, if you want to use a different name, you can let Eloquent know that by defining
a table property like this:
@extends('master')
@section('title', 'Contact')
@section('content')
<div class="container col-md-8 col-md-offset-2">
<div class="well well bs-component">
<form class="form-horizontal">
<fieldset>
<legend>Submit a new ticket</legend>
<div class="form-group">
<label for="title" class="col-lg-2 control-label">Title<\
/label>
<div class="col-lg-10">
<input type="text" class="form-control" id="title" p\
laceholder="Title">
</div>
</div>
<div class="form-group">
<label for="content" class="col-lg-2 control-label">Cont\
ent</label>
<div class="col-lg-10">
<textarea class="form-control" rows="3" id="content"\
></textarea>
<span class="help-block">Feel free to ask us any que\
stion.</span>
</div>
</div>
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<button class="btn btn-default">Cancel</button>
<button type="submit" class="btn btn-primary">Submit\
</button>
</div>
</div>
</fieldset>
</form>
</div>
</div>
@endsection
Unfortunately, we cant see this view yet, we have to use a Controller action to display it. Open
PagesController.php, edit:
Chapter 3: Building A Support Ticket System 99
to
By default, Laravel has created some RESTful actions (create, edit, update, etc.) for us. We will use
some actions, so you dont need to delete them all.
Update the create action as follows:
Route::get('/contact', 'TicketsController@create');
A new TicketFormRequest will be generated! You can find it in the app/Http/Requests directory.
Open the file, you can see that there are two methods: authorize and rules.
authorize() method
By default, it returns false. That means no one can be able to perform the request. To be able to
submit the tickets, we have to turn it to true
rules() method
required|min:3 validation rule means that the users must fill the title field, and the title should have
a minimum three character length.
There are many validation rules, you can see a list of available rules at:
http://laravel.com/docs/master/validation#available-validation-rules
Chapter 3: Building A Support Ticket System 102
HTML: HTML helpers for creating common HTML and form elements
Annotations: route and events annotations.
Remote: a simple way to SSH into remote servers and run commands.
Fortunately, bringing all these features back is very easy. You just need to install LaravelCollective
package!
http://laravelcollective.com
Dont know how to install the package? Let me show you.
{
"name": "laravel/laravel",
"description": "The Laravel Framework.",
"keywords": ["framework", "laravel"],
"license": "MIT",
"type": "project",
"require": {
"php": ">=5.5.9",
"laravel/framework": "5.1.*"
},
"require-dev": {
"fzaninotto/faker": "~1.4",
"mockery/mockery": "0.9.*",
"phpunit/phpunit": "~4.0",
"phpspec/phpspec": "~2.1"
},
"autoload": {
"classmap": [
"database"
],
"psr-4": {
"App\\": "app/"
Chapter 3: Building A Support Ticket System 103
}
},
"autoload-dev": {
"classmap": [
"tests/TestCase.php"
]
},
"scripts": {
"post-install-cmd": [
"php artisan clear-compiled",
"php artisan optimize"
],
"post-update-cmd": [
"php artisan clear-compiled",
"php artisan optimize"
],
"post-root-package-install": [
"php -r \"copy('.env.example', '.env');\""
],
"post-create-project-cmd": [
"php artisan key:generate"
]
},
"config": {
"preferred-install": "dist"
},
"minimum-stability": "dev",
"prefer-stable": true
}
This is a JSON (Javascript Object Notation) file. We use JSON to store and exchange data. JSON
is very easy to read. If you can read HTML or XML, Im sure that you can read JSON.
If you cant read it, learn more about JSON here:
www.w3schools.com/json
In this section, we will add the HTML package to our app. The instructions can be found here:
http://laravelcollective.com/docs/5.1/html
To install a Laravel package using Composer, you just need to add the following code:
find:
Chapter 3: Building A Support Ticket System 104
"require": {
"php": ">=5.5.9",
"laravel/framework": "5.1.*"
},
add:
"require": {
"php": ">=5.5.9",
"laravel/framework": "5.1.*",
"laravelcollective/html": "5.1.*"
},
Note: If youre using Laravel 5.2 or newer, the version could be different. For example,
if youre using Laravel 5.2, the code should be laravelcollective/html: 5.2.*
Save the file and run this command at your application root:
composer update
'providers' => [
/*
* Laravel Framework Service Providers...
*/
Illuminate\Foundation\Providers\ArtisanServiceProvider::class,
Illuminate\Auth\AuthServiceProvider::class,
Illuminate\Broadcasting\BroadcastServiceProvider::class,
Illuminate\Bus\BusServiceProvider::class,
Illuminate\Cache\CacheServiceProvider::class,
Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
Chapter 3: Building A Support Ticket System 105
Illuminate\Routing\ControllerServiceProvider::class,
Illuminate\Cookie\CookieServiceProvider::class,
Illuminate\Database\DatabaseServiceProvider::class,
Illuminate\Encryption\EncryptionServiceProvider::class,
Illuminate\Filesystem\FilesystemServiceProvider::class,
Illuminate\Foundation\Providers\FoundationServiceProvider::class,
Illuminate\Hashing\HashServiceProvider::class,
Illuminate\Mail\MailServiceProvider::class,
Illuminate\Pagination\PaginationServiceProvider::class,
Illuminate\Pipeline\PipelineServiceProvider::class,
Illuminate\Queue\QueueServiceProvider::class,
Illuminate\Redis\RedisServiceProvider::class,
Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
Illuminate\Session\SessionServiceProvider::class,
Illuminate\Translation\TranslationServiceProvider::class,
Illuminate\Validation\ValidationServiceProvider::class,
Illuminate\View\ViewServiceProvider::class,
/*
* Application Service Providers...
*/
App\Providers\AppServiceProvider::class,
App\Providers\EventServiceProvider::class,
App\Providers\RouteServiceProvider::class,
],
Collective\Html\HtmlServiceProvider::class,
App\Providers\RouteServiceProvider::class,
Collective\Html\HtmlServiceProvider::class,
],
'aliases' => [
],
<form action="contact">
<label>First name:</label>
<input type="text" name="firstname" value="Enter your first name">
<br />
<label>Last name:</label>
<input type="text" name="lastname" value="Enter your last name">
<br />
<input type="submit" value="Submit">
</form>
As you see, we use Form::open() to create our opening form tag and Form::close() to close the form.
Text fields and labels can be generated using Form::text and Form::label method.
You can learn more about how to use HTML package by reading Laravel 4 official docs:
http://laravel.com/docs/4.2/html
If you dont like to take advantage of the HTML package to build your forms, you dont have to use
it. I just want you to understand its syntax because many Laravel developers are using it these days.
It would be better if you know both methods.
Chapter 3: Building A Support Ticket System 108
Since Laravel 5.2, /app/Http/Kernel.php and /app/Http/routes.php have been changed. You could
get some errors like:
/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| This route group applies the "web" middleware group to every route
| it contains. The "web" middleware group is defined in your HTTP
| kernel and includes session state, CSRF protection, and more.
|
*/
Route::group(['middleware' => ['web']], function () {
//
});
If youre using Session ($errors object, session(status), etc.) or CSRF protection, be sure to put all
the related routes inside the web middleware group. For example:
If you see:
Route::get('/contact', 'TicketsController@create');
Route::post('/contact', 'TicketsController@store');
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
];
Change to:
Chapter 3: Building A Support Ticket System 110
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
];
Route::get('/contact', 'TicketsController@create');
But we wont use GET to submit data. GET requests should only be used to retrieve data.
We always use POST method to handle the form submissions endpoints. When we use POST,
requests are never cached, parameters are not saved in users browser history. Therefore, POST
is safer than GET.
Lets open the routes.php file, add:
Route::post('/contact', 'TicketsController@store');
Good! Now when users make a POST request to the contact page, this route tells Laravel to execute
the TicketsControllers store action.
The store action is still empty. You can update it to display the form data:
TicketsController.php
Chapter 3: Building A Support Ticket System 111
We use the TicketFormRequest as a parameter of the store action here to tell Laravel that we
want to apply validation to the store action.
Laravel requires us to type-hint the IlluminateHttpRequest class on our controller constructor to
obtain an instance of the current HTTP request. Simply put, we need to add this line at the top of
the TicketsController.php file:
use App\Http\Requests\TicketFormRequest;
find:
add above
use App\Http\Requests\TicketFormRequest;
class TicketsController extends Controller
{
One more step, you need to update the ticket form to send POST requests. Open tickets/cre-
ate.blade.php.
find:
<form class="form-horizontal">
update to:
update to:
Good! Refresh your browser, fill the form and hit submit again, youll see:
Chapter 3: Building A Support Ticket System 114
add below:
Basically, if the validator fails, Laravel will store all errors in the session. We can easily access the
errors via $errors object.
Now, lets go back to the form, dont fill anything and hit the submit button:
Display error
@extends('master')
@section('title', 'Create a new ticket')
@section('content')
<div class="container col-md-8 col-md-offset-2">
<div class="well well bs-component">
<fieldset>
<legend>Submit a new ticket</legend>
<div class="form-group">
<label for="title" class="col-lg-2 control-label">Title<\
/label>
<div class="col-lg-10">
<input type="title" class="form-control" id="title" \
placeholder="Title" name="title">
</div>
</div>
<div class="form-group">
<label for="content" class="col-lg-2 control-label">Cont\
ent</label>
<div class="col-lg-10">
<textarea class="form-control" rows="3" id="content"\
name="content"></textarea>
<span class="help-block">Feel free to ask us any que\
stion.</span>
</div>
</div>
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<button class="btn btn-default">Cancel</button>
<button type="submit" class="btn btn-primary">Submit\
</button>
</div>
Chapter 3: Building A Support Ticket System 117
</div>
</fieldset>
</form>
</div>
</div>
@endsection
APP_ENV=local
APP_DEBUG=true
APP_KEY=o8UTlUkakeVkSUlFbGjSXaCcmAAkU0xB
DB_HOST=localhost
DB_DATABASE=homestead
DB_USERNAME=homestead
DB_PASSWORD=secret
CACHE_DRIVER=file
SESSION_DRIVER=file
QUEUE_DRIVER=sync
Chapter 3: Building A Support Ticket System 118
MAIL_DRIVER=smtp
MAIL_HOST=mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
As you see, the file is very clear. Lets try to edit a few settings.
Currently, youre using the default homestead database. If youve created a different database and
you want to use it instead, edit this line:
DB_DATABASE=homestead
to
DB_DATABASE=yourCustomDatabaseName
If you dont want to display full error messages, turn the APP_DEBUG to false.
If youre using sendgrid to send emails, replace these lines with your sendgrid credentials:
MAIL_DRIVER=smtp
MAIL_HOST=mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
For example:
MAIL_DRIVER=smtp
MAIL_HOST=smtp.sendgrid.net
MAIL_PORT=587
MAIL_USERNAME=learninglaravel
MAIL_PASSWORD=secret
use App\Ticket;
use App\Ticket;
class TicketsController extends Controller
{
This tells Laravel that you want to use your Ticket model in this class.
Now you can use Ticket model to store the form data. Update the store action:
$ticket->save();
$slug = uniqid();
We use the uniqid() function to generate a unique ID based on the microtime. You may use md5()
function to generate the slugs or create your custom slugs.
This is the tickets unique ID.
Chapter 3: Building A Support Ticket System 120
Next, we create a new Ticket model instance, set attributes on the model.
$ticket->save();
Then we call the save method to save the data to our database.
Once the ticket has been saved, we redirect users to the contact page with a message.
Finally, try to create a new ticket and submit it.
Display error
Chapter 3: Building A Support Ticket System 121
Oh no!
There is an error: MassAssignmentException
Dont worry, its a Laravel feature that protect against mass-assignment.
What is mass-assignment?
According to the Laravel official docs:
mass-assignment vulnerability occurs when users pass unexpected HTTP parameters through a
request, and then that parameter changes a column in your database you did not expect. For example,
a malicious user might send an is_admin parameter through an HTTP request, which is then mapped
onto your models create method, allowing the user to escalate themselves to an administrator
Read more about it here:
http://laravel.com/docs/master/eloquent#mass-assignment
To save the ticket, open the Ticket model. (Ticket.php file)
Then place the following contents into the Ticket Model:
One more thing to do, we need to update the tickets/create.blade.php view to display the status
message:
Find:
Chapter 3: Building A Support Ticket System 122
Add Below:
@if (session('status'))
<div class="alert alert-success">
{{ session('status') }}
</div>
@endif
Success message
Success message
Route::get('/tickets', 'TicketsController@index');
When users access homestead.app/tickets, we use TicketsController to execute the index action.
Feel free to change the link path or the actions name to whatever you like.
Then, open the TicketsController file, update the index action
Chapter 3: Building A Support Ticket System 125
We use Ticket::all() to get all tickets in our database and store them in the $tickets variable.
Before we return the tickets.index view, we use the compact() method to convert the result to an
array, and pass it to the view.
Alternatively, you can use:
or
@extends('master')
@section('title', 'View all tickets')
@section('content')
<tbody>
@foreach($tickets as $ticket)
<tr>
<td>{!! $ticket->id !!} </td>
<td>{!! $ticket->title !!}</td>
<td>{!! $ticket->status ? 'Pending' : 'Answe\
red' !!}</td>
</tr>
@endforeach
</tbody>
</table>
@endif
</div>
</div>
@endsection
@if ($tickets->isEmpty())
<p> There is no ticket.</p>
@else
First, we check if the $tickets variable is empty or not. If its empty, then we display a message to
our users.
@else
<table class="table">
<thead>
<tr>
<th>ID</th>
<th>Title</th>
<th>Status</th>
</tr>
</thead>
<tbody>
@foreach($tickets as $ticket)
<tr>
<td>{!! $ticket->id !!} </td>
<td>{!! $ticket->title !!}</td>
<td>{!! $ticket->status ? 'Pending' : 'Answered' !!}</td>
</tr>
Chapter 3: Building A Support Ticket System 127
@endforeach
</tbody>
</table>
@endif
If the $tickets is not empty, we use foreach() loop to display all tickets.
Here is how we can write the if else statement in a short way. If the tickets status is 1, we say that
its pending. If the tickets status is 0, we say that its answered.
Feel free to change the name of the status to your liking.
Go to homestead.app/tickets, you should be able to view all tickets that youve created!
All tickets
Chapter 3: Building A Support Ticket System 128
Route::get('/ticket/{slug?}', 'TicketsController@show');
You should notice that we use a special route (/ticket/{slug?}) here. By doing this, we tell Laravel
that any route parameter named slug will be bound to the show action of our TicketsController.
Simply put, when we visit ticket/558467e731bb8, Laravel automatically detects the slug (which is
558467e731bb8) and pass it to the action.
Note: you can change {slug?} to {slug} or whatever you like. Be sure to put your custom
name in the { } brackets.
We pass the slug of the ticket we want to display in the show action. Then we can use this slug to
find the correct ticket via our Ticket models firstOrFail method.
The firstOrFail method will retrieve the first result of the query. If there is no result, it will throw
a ModelNotFoundException.
If you dont want to throw an exception, you can use the first() method.
$ticket = Ticket::whereSlug($slug)->first();
@extends('master')
@section('title', 'View a ticket')
@section('content')
@endsection
A single ticket
Note: your tickets slug may be different. Be sure to use a correct slug to view the ticket.
@foreach($tickets as $ticket)
<tr>
<td>{!! $ticket->id !!} </td>
<td>{!! $ticket->title !!}</td>
<td>{!! $ticket->status ? 'Pending' : 'Answered' !!}</td>
</tr>
@endforeach
Update to:
@foreach($tickets as $ticket)
<tr>
<td>{!! $ticket->id !!}</td>
<td>
<a href="{!! action('TicketsController@show', $ticket->slug) !!}">{!\
! $ticket->title !!} </a>
</td>
<td>{!! $ticket->status ? 'Pending' : 'Answered' !!}</td>
</tr>
@endforeach
Here, we use action function to generate a URL for the TicketsControllers show action:
action('TicketsController@show', $ticket->slug)
The second argument is a route parameter. We use slug to find the ticket, so we put the tickets
slug here.
Alternatively, you can write the code like this:
Now, when you access homestead.app/tickets, you can click on the title to view the ticket.
Chapter 3: Building A Support Ticket System 132
Edit a ticket
Its time to move on to create our ticket edit form.
Open routes.php, add this route:
Route::get('/ticket/{slug?}/edit','TicketsController@edit');
We find the ticket using its slug, then we use the tickets.edit view to display the edit form.
Lets create our edit view at resouces/views/tickets/edit.blade.php:
@extends('master')
@section('title', 'Edit a ticket')
@section('content')
<div class="container col-md-8 col-md-offset-2">
<div class="well well bs-component">
@if (session('status'))
<div class="alert alert-success">
{{ session('status') }}
</div>
@endif
<fieldset>
<legend>Edit ticket</legend>
<div class="form-group">
<label for="title" class="col-lg-2 control-label">Title<\
/label>
<div class="col-lg-10">
<input type="text" class="form-control" id="title" n\
ame="title" value="{!! $ticket->title !!}">
</div>
</div>
<div class="form-group">
<label for="content" class="col-lg-2 control-label">Cont\
Chapter 3: Building A Support Ticket System 134
ent</label>
<div class="col-lg-10">
<textarea class="form-control" rows="3" id="content"\
name="content">{!! $ticket->content !!}</textarea>
</div>
</div>
<div class="form-group">
<label>
<input type="checkbox" name="status" {!! $ticket->st\
atus?"":"checked"!!} > Close this ticket?
</label>
</div>
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<button class="btn btn-default">Cancel</button>
<button type="submit" class="btn btn-primary">Update\
</button>
</div>
</div>
</fieldset>
</form>
</div>
</div>
@endsection
This view is very similar to the create view, but we add a new checkbox to modify tickets status.
<div class="form-group">
<label>
<input type="checkbox" name="status" {!! $ticket->status?"":"checked"!!}\
> Close this ticket?
</label>
</div>
{!! $ticket->status?"":"checked"!!}
If the status is 1 (pending), we display nothing, the checkbox is not checked. If the status is 0
(answered) , we display a checked attribute, the checkbox is checked.
Good! Now, lets open the show view, update the edit button as follows:
Chapter 3: Building A Support Ticket System 135
We use the action helper again! When you click on the edit button, you should be able to access the
edit form:
Edit form
Unfortunately, we cant update the ticket yet. Remember what youve done to create a new ticket?
We need to use POST method to submit the form.
Open routes.php, add:
Route::post('/ticket/{slug?}/edit','TicketsController@update');
Then use update action to handle the submission and store the changes.
Chapter 3: Building A Support Ticket System 136
As you notice, you can save the ticket by using the following code:
$ticket = Ticket::whereSlug($slug)->firstOrFail();
$ticket->title = $request->get('title');
$ticket->content = $request->get('content');
if($request->get('status') != null) {
$ticket->status = 0;
} else {
$ticket->status = 1;
}
$ticket->save();
This is how we can check if the users select the status checkbox or not:
if($request->get('status') != null) {
$ticket->status = 0;
} else {
$ticket->status = 1;
}
Try to edit the ticket now and hit the update button!
Delete a ticket
Youve learned how to create, read and update a ticket. Next, you will learn how to delete it. By the
end of this section, youll have a nice CRUD application!
First step, lets open the routes.php file:
Route::post('/ticket/{slug?}/delete','TicketsController@destroy');
When we send a POST request to this route, Laravel will take the slug and execute the TicketsCon-
trollers destroy action.
Chapter 3: Building A Support Ticket System 138
We find the ticket using the provided slug. After that, we use $ticket->delete() method to delete the
ticket.
As always, we then redirect users to the all tickets page. Lets update the index.blade.php to display
the status message:
Find:
<div class="panel-heading">
<h2> Tickets </h2>
</div>
Add below:
@if (session('status'))
<div class="alert alert-success">
{{ session('status') }}
</div>
@endif
Finally, in order to remove the ticket, all we need to do is create a form to submit a delete request.
Open show.blade.php and find:
Update to:
Chapter 3: Building A Support Ticket System 139
The code above creates a nice delete form for you. When you view a ticket, you should see a different
delete button:
Chapter 3: Building A Support Ticket System 140
Now, click the delete button, you should be able to remove the ticket!
Chapter 3: Building A Support Ticket System 141
Sending an email
When users submit a ticket, we may want to receive an email to get notified. In this section, you
will learn how to send emails using Laravel.
Laravel provides many methods to send emails. You may use a plain PHP method to send emails, or
you may use some email service providers such as Mailgun, Sendgrid, Mandrill, Amazon SES, etc.
To send emails on a production server, simply edit the mail.php configuration file, which is placed
in the config directory.
Here is the file without comments:
Chapter 3: Building A Support Ticket System 142
return [
To send emails on a local development server (Homestead), simply edit the .env file.
MAIL_DRIVER=mail
MAIL_HOST=mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null
As usual, you may learn how to use Mailgun, Mandrill and SES drivers at the official docs:
http://laravel.com/docs/master/mail
Because were working on Homestead, we will learn how to send emails on Homestead using Gmail
and Sendgrid for FREE!!!!!
Take a look at the Sign-in & security -> Connected apps & sites -> Allow less secure apps settings.
You must turn the option Allow less secure apps ON.
Configure Gmail
MAIL_DRIVER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=yourEmail
MAIL_PASSWORD=yourPassword
MAIL_ENCRYPTION=tls
MAIL_DRIVER=smtp
MAIL_HOST=smtp.sendgrid.net
MAIL_PORT=587
MAIL_USERNAME=yourSendgridUsername
MAIL_PASSWORD=yourPassword
Route::get('sendemail', function () {
$data = array(
'name' => "Learning Laravel",
);
});
});
As you see, we use the send method on the Mail facade. There are three arguments:
When you visit http://homestead.app/sendemail, Laravel will try to send an email. If the email is
sent successfully, Laravel will display a message.
Finally, we dont have the welcome.blade.php view yet, lets create it and put it in the emails
directory.
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
</head>
<body>
<h2>Learning Laravel!</h2>
<div>
Welcome to {!! $name !!} website!
</div>
</body>
</html>
Because weve passed an array containing the $name key in the above route, we could display the
name within this welcome view using:
or
Add above:
Chapter 3: Building A Support Ticket System 147
$data = array(
'ticket' => $slug,
);
And dont forget to tell Laravel that you want to use the Mail facade here:
Find:
Add above:
use Illuminate\Support\Facades\Mail;
As you may notice, we dont have the emails/ticket.blade.php view yet. Lets create it!
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
</head>
<body>
<h2>Learning Laravel!</h2>
<div>
You have a new ticket. The ticket id is {!! $ticket !!}!
</div>
</body>
</html>
Reply to a ticket
Welcome to the last section!
In this section, we will learn how to create a form for users to post a reply.
<?php
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
$table->tinyInteger('status')->default(1);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::drop('comments');
}
}
You should know how to read this file by now. Lets run the migrate command to create the
comments table and its columns:
Great! Check your database now to make sure that you have created the comments table.
Chapter 3: Building A Support Ticket System 150
Comments table
One to One
One to Many
Many to Many
Has Many Through
Polymorphic Relations
Many To Many Polymorphic Relations
What is a relationship?
Usually, tables are related to each other. For instance, our tickets may have many comments (ticket
responses). That is One to Many relationship.
Once weve defined a One to Many relationship between tickets and comments table, we can easily
access and list all comments or any related records.
Chapter 3: Building A Support Ticket System 151
In addition, we may want to make all columns mass assignable except the id column:
Instead of using the $fillable property, we use the $guarded property here.
You now have:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
By doing this, we let Eloquent know that this Comment model belongs to the Ticket model.
Next, open the Ticket model and add:
Chapter 3: Building A Support Ticket System 152
As you may have guessed, we tell that the Ticket model has many comments and Eloquent can use
the post_id (ticket id) to find all related comments.
Thats it! Youve defined a One to Many relationship between two tables.
Route::post('/comment', 'CommentsController@newComment');
When we send a POST request to this route, Laravel will execute the CommetsControllers
newComment action.
Its time to run this command to generate our controller:
Open the new CommentsController. Remove all default actions and create a new one:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Http\Requests\CommentFormRequest;
use App\Comment;
$comment->save();
Here is a little tip, you can use redirect()->back() to redirect users back to the previous page!
As you see, we still use Request here for the validation.
Create CommentFormRequest
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
/**
* Get the validation rules that apply to the request.
*
* @return array
*/
public function rules()
{
return [
'content'=> 'required|min:3',
];
}
}
@foreach($errors->all() as $error)
<p class="alert alert-danger">{{ $error }}</p>
@endforeach
@if(session('status'))
<div class="alert alert-success">
{{ session('status') }}
</div>
@endif
<fieldset>
<legend>Reply</legend>
<div class="form-group">
<div class="col-lg-12">
<textarea class="form-control" rows="3" id="content"\
name="content"></textarea>
</div>
</div>
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<button type="reset" class="btn btn-default">Cancel<\
/button>
<button type="submit" class="btn btn-primary">Post</\
button>
</div>
</div>
</fieldset>
</form>
</div>
This form is very similar to the create ticket form, we just need to add a new hidden input to
submit the ticket id (post_id) as well.
When you have the form, lets try to reply to a ticket.
Chapter 3: Building A Support Ticket System 156
Create CommentFormRequest
As you may see in the code above, we just need to use this line to list all comments:
$comments = $ticket->comments()->get();
@foreach($comments as $comment)
<div class="well well bs-component">
<div class="content">
{!! $comment->content !!}
</div>
</div>
@endforeach
@extends('master')
@section('title', 'View a ticket')
@section('content')
@foreach($comments as $comment)
<div class="well well bs-component">
<div class="content">
{!! $comment->content !!}
</div>
</div>
@endforeach
@foreach($errors->all() as $error)
<p class="alert alert-danger">{{ $error }}</p>
@endforeach
@if(session('status'))
<div class="alert alert-success">
{{ session('status') }}
</div>
@endif
<fieldset>
<legend>Reply</legend>
<div class="form-group">
<div class="col-lg-12">
<textarea class="form-control" rows="3" id="cont\
Chapter 3: Building A Support Ticket System 159
ent" name="content"></textarea>
</div>
</div>
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<button type="reset" class="btn btn-default">Can\
cel</button>
<button type="submit" class="btn btn-primary">Po\
st</button>
</div>
</div>
</fieldset>
</form>
</div>
</div>
@endsection
A new reply
Chapter 3 Summary
In this chapter, youve gone through the different steps involved in creating a ticket support system.
Even though the app is simple, it provides us many things to learn:
Basically, you may now be able to create a simple blog system. Feel free to build a different
application or customize this application to meet your needs.
The next chapter is where all the fun begin! You will learn to create a complete blog application that
has an admin control panel. You may use this application to write your blog posts or you may use
it as a starter template for all your amazing applications.
Chapter 4: Building A Blog Application
Up to this point, we have used many Laravel features to build our applications. In this chapter, were
going to build a blog application. By doing this, we will learn about Laravel Authentication, Seeding,
Localization, Middleware and many useful features that can help us to have a solid understanding
about Laravel 5.
For our purposes, its always best to think about how our blog application works first.
163
Chapter 4: Building A Blog Application 164
Route::get('users/register', 'Auth\AuthController@getRegister');
Route::post('users/register', 'Auth\AuthController@postRegister');
The first route will provide the registration form. The second route will process the form. Both
routes are handled by the AuthControllers actions: getRegister and postRegister.
By default, Laravel has created the AuthController for us. You can find it in the Auth directory.
Lets open the file and take a look at:
As you may notice, there are three fields here: name, email and password.
When users visit users/register, this AuthController will render a registration view, which contains
a registration form.
Unfortunately, Laravel doesnt create the registration view for us, we have to create it manually.
The registration views should be placed at resources/views/auth/register.blade.php.
Here is the code:
@extends('master')
@section('name', 'Register')
@section('content')
<div class="container col-md-6 col-md-offset-3">
<div class="well well bs-component">
<fieldset>
Chapter 4: Building A Blog Application 165
<legend>Register an account</legend>
<div class="form-group">
<label for="name" class="col-lg-2 control-label">Name</l\
abel>
<div class="col-lg-10">
<input type="text" class="form-control" id="name" pl\
aceholder="Name" name="name" value="{{ old('name') }}">
</div>
</div>
<div class="form-group">
<label for="email" class="col-lg-2 control-label">Email<\
/label>
<div class="col-lg-10">
<input type="email" class="form-control" id="email" \
placeholder="Email" name="email" value="{{ old('email') }}">
</div>
</div>
<div class="form-group">
<label for="password" class="col-lg-2 control-label">Pas\
sword</label>
<div class="col-lg-10">
<input type="password" class="form-control" name="p\
assword">
</div>
</div>
<div class="form-group">
<label for="password" class="col-lg-2 control-label">Con\
firm password</label>
<div class="col-lg-10">
<input type="password" class="form-control" name="p\
assword_confirmation">
</div>
</div>
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<button type="reset" class="btn btn-default">Cancel<\
/button>
<button type="submit" class="btn btn-primary">Submit\
Chapter 4: Building A Blog Application 166
</button>
</div>
</div>
</fieldset>
</form>
</div>
</div>
@endsection
Youve created many forms in the previous chapters, so I guess you should understand this file
clearly.
Here is a new tip. Instead of using this line to generate a new CSRF token:
You can simply use this helper function to generate the token!
You also may notice that there is a new old() method. When the forms validation fails, the users
will be redirected back to the form. We use this method to display the old users input, so they dont
have to fill in all the fields again.
Now, go to http://homestead.app/users/register, you should see a nice user registration form.
Chapter 4: Building A Blog Application 167
Fill in all the fields, and hit submit! Youve registered a new user!
Check your database now, you should see:
Chapter 4: Building A Blog Application 168
A new user
By default, Laravel automatically redirects you to the /home URI. If you see this error when youre
at http://homestead.app/home:
Then that means your routes.php file doesnt have the home route:
Route::get('home', 'PagesController@home');
You can fix this error by adding the home route into your app or you may simply ignore it. Youll
learn how to redirect users to other locations in the next section.
use AuthenticatesAndRegistersUsers;
You may notice that when you go to the registration page, Laravel will automatically redirect you
back to the home page because youre now logged in.
Note: In Laravel 5.2, the $redirectPath variable has been changed to $redirectTo.
We dont have the logout functionality yet, but dont worry, its very easy to implement.
Open the shared/navbar.blade.php view, find:
<li><a href="/users/register">Register</a></li>
<li><a href="/users/login">Login</a></li>
@if (Auth::check())
<li><a href="/users/logout">Logout</a></li>
@else
<li><a href="/users/register">Register</a></li>
<li><a href="/users/login">Login</a></li>
@endif
To check whether a user is logged in, we can use the Auth::check() method. In the code above, if
users are logged in, we will display a logout link.
Chapter 4: Building A Blog Application 170
A logout link
Route::get('users/logout', 'Auth\AuthController@getLogout');
If youre using Laravel 5.2, open your AuthController, update the constructor (aka construct
method) as follows:
Chapter 4: Building A Blog Application 171
As you see, when users visit the users/logout link, we will use AuthControllers getLogout action
to log the users out.
A new user
Try to test the functionality yourself! Now you can be able to log out!
Chapter 4: Building A Blog Application 172
Route::get('users/login', 'Auth\AuthController@getLogin');
Route::post('users/login', 'Auth\AuthController@postLogin');
The GET route will display the login form, the POST route will process the form.
As you may have guessed, you should create a login view now. The view should be placed at
views/auth/login.blade.php.
@extends('master')
@section('name', 'Login')
@section('content')
<div class="container col-md-6 col-md-offset-3">
<div class="well well bs-component">
<fieldset>
<legend>Login</legend>
<div class="form-group">
<label for="email" class="col-lg-2 control-label">Email<\
/label>
<div class="col-lg-10">
<input type="email" class="form-control" id="email" \
name="email" value="{{ old('email') }}">
</div>
</div>
<div class="form-group">
<label for="password" class="col-lg-2 control-label">Pas\
Chapter 4: Building A Blog Application 173
sword</label>
<div class="col-lg-10">
<input type="password" class="form-control" name="p\
assword">
</div>
</div>
<div class="checkbox">
<label>
<input type="checkbox" name="remember" > Remember Me?
</label>
</div>
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<button type="submit" class="btn btn-primary">Login<\
/button>
</div>
</div>
</fieldset>
</form>
</div>
</div>
@endsection
Our login form is simple, it has two fields: email and password. Users have to enter the correct
email and password here to login.
Laravel also provides the remember me functionality out of the box. We can implement it by simply
creating a remember checkbox.
Well done. Now lets go to http://homestead.app/users/login and try to login with your email and
password!
Chapter 4: Building A Blog Application 174
Login form
If you try to login with a wrong information, you may encounter this error:
Chapter 4: Building A Blog Application 175
Error login
By default, Laravel use auth/login route to authenticate users, and users will be redirected to that
route if they enter wrong credentials. However, we use users/login route, so we need to let Laravel
know that by opening the AuthController class and adding a loginPath property:
Note: If youre using Laravel 5.1.4 or newer, this feature has been implemented already.
You may skip these steps. By the way, Its still good to know how it works.
As were using the AuthController class for authentication, you can easily integrate this feature by
doing the following steps:
First, be sure to update your application to version 5.1.4 or newer. You can update your application
by vagrant ssh to your VM, then cd to your Laravel root directory, and run:
composer update
use App\Http\Controllers\Controller;
Add below:
use Illuminate\Foundation\Auth\ThrottlesLogins;
Find:
use AuthenticatesAndRegistersUsers;
Modify to:
Wrong credentials
Chapter 4: Building A Blog Application 178
When you try to login many times, there would be an error message:
By using Route::group we can group all related routes together and apply some specific rules for
them.
We use the prefix attribute to prefix each route in the route group with a URI (admin). In this case,
when we go to http://homestead.app/admin or any routes that contain the admin prefix, Laravel will
understand that we want to access the admin area.
Laravel 5.1 uses PSR-2 autoloading standard, which is a coding style. Your applications controllers,
models and other classes must be namespaced.
What are namespaces? According to PHP docs: namespaces are designed to solve two problems
that authors of libraries and applications encounter when creating re-usable code elements
such as classes or functions.. Simply put, lets think namespaces as the last names of persons.
When many persons have the same name, we will use their last name to distinguish them apart.
To namespace a class, we can use the namespace keyword and declare the namespace at the top of
the file before any other code. For instance, lets open AuthController.php class, you should see its
namespace:
<?php
namespace App\Http\Controllers\Auth;
<?php
namespace App\Http\Controllers\Admin;
Laravel will know exactly which class that we want to load and where to find it.
Laravel 5 also has a new feature called HTTP Middleware (or simply Middleware). Basically, we
use it to filter our applications HTTP requests. For example, I use:
Chapter 4: Building A Blog Application 180
That means I want to use the auth middeware for this route group. Only authenticated users can
access these routes. Well learn more about Middleware soon.
Route::get('users', 'UsersController@index');
We dont have the UsersController yet, lets use PHP Artisan to create it:
This time, our code is a little bit different. It has /Admin before the controllers name. Laravel is
clever. When we code like this, it will automatically create a directory called Admin, and put the
UsersController file into the Admin directory for you. More than that, our controller has been
namespaced!
UsersController
At this point, I think that youve known how to list all the users. Basically, the process is very similar
to what weve done to list all the tickets in Chapter 3.
First, we tell Laravel that we want to use the User model:
Find:
Chapter 4: Building A Blog Application 181
use App\Http\Controllers\Controller;
Add below:
use App\User;
As you may have guessed, we will put all the administration views in the backend directory.
Were going to create a new view called index.blade.php to display all the users. Lets create a new
users directory as well and put the index view inside.
So the index view will be placed at views/backend/users/index.blade.php.
Here is the code:
@extends('master')
@section('title', 'All users')
@section('content')
<th>ID</th>
<th>Name</th>
<th>Email</th>
<th>Joined at</th>
</tr>
</thead>
<tbody>
@foreach($users as $user)
<tr>
<td>{!! $user->id !!}</td>
<td>
<a href="#">{!! $user->name !!} </a>
</td>
<td>{!! $user->email !!}</td>
<td>{!! $user->created_at !!}</td>
</tr>
@endforeach
</tbody>
</table>
@endif
</div>
</div>
@endsection
We can use middleware to do many things. For example, middleware can help to authenticate users,
log data for analytics, add CSRF protection, etc.
You can find all middleware in the app/Http/Middleware directory. Open the directory, youll see
four middleware:
Weve used the Authenticated middleware for our admin route group. Lets open it:
return $next($request);
}
As you see, this Authenticated middleware is just a class. We use the handle method to process
all requests and define request filters.
By default, if users are not signed in, the middleware automatically redirects users to the auth/login
URI.
return redirect()->guest('auth/login');
However, we use users/login route to access our login page. Thats why Laravel doesnt understand
where the auth/login route is, and it throws an error.
To fix the bug, we can just modify the line to:
return redirect()->guest('users/login');
When you login with wrong credentials, you are redirected to the users/login route. Everything
should be good to go.
Now lets say that we wanted to use a new middleware called Manager to make sure that only
administrators can access the admin area.
Chapter 4: Building A Blog Application 186
A new middleware called Manager will be created. You can find it in the Middleware directory.
<?php
namespace App\Http\Middleware;
use Closure;
class Manager
{
public function handle($request, Closure $next)
{
return $next($request);
}
}
One more step to do, we need to register the Manager middleware. Lets open the Kernel.php file,
which can be found in the Http directory.
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
];
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
];
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
\Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
\App\Http\Middleware\Manager::class,
];
However, we just want to assign the Manager middleware to our admin route group. Therefore, all
we need to do is append the Manager middleware to the $routeMiddleware property.
protected $routeMiddleware = [
'auth' => \App\Http\Middleware\Authenticate::class,
'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
'manager' => \App\Http\Middleware\Manager::class,
];
Note:: Dont append the Manager middleware to the $middleware property. Only
append the middleware to the $routeMiddleware property, because we only want to
use it for our admin route group.
Next, open routes.php and modify the admin route group to enable the Manager middleware:
Change to:
Well done! Youve got a solid foundation of Middleware. Keep in mind that you can use Middleware
to do many things.
Even though our Manager middleware is working properly, we cant see any difference. The reason
is, we dont create any request filters yet.
If we want to restrict access to the admin area, we need to add roles or permissons to our users.
Fortunately, Laravel has a very popular package that can help us to implement the feature easily:
Entrust.
The official Entrust package now supports Laravel 5.2. If you have any issues, please submit your
issues or view other issues at:
https://github.com/Zizaco/entrust/issues
Follow the steps below to install Entrust:
In order to install Entrust for Laravel 5.2, find the require section in your composer.json file, add
this line:
"zizaco/entrust": "5.2.x-dev"
"require": {
"php": ">=5.5.9",
"laravel/framework": "5.2.*",
"laravelcollective/html": "5.2.*",
"zizaco/entrust": "5.2.x-dev"
},
Zizaco\Entrust\EntrustServiceProvider::class,
If you are going to use Middleware (requires Laravel 5.1+), find routeMiddleware array in
app/Http/Kernel.php and add:
Run this command to create a new entrust.php file, which can be found in the config directory.
You may use this file to customize table names and model namespaces.
Entrust need some database tables to work. Run this command to generate the migrations:
use Zizaco\Entrust\EntrustRole;
Create a new file called Permission.php, place it inside the app directory.
use Zizaco\Entrust\EntrustPermission;
<?php
namespace App;
<?php
namespace App;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Zizaco\Entrust\Traits\EntrustUserTrait;
Chapter 4: Building A Blog Application 191
use EntrustUserTrait;
This is Entrust trait. When you add it to the User model, you can use the following methods: roles(),
hasRole($name), can($permission), and ability($roles, $permissions, $options).
You should have something like this:
<?php
namespace App;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Zizaco\Entrust\Traits\EntrustUserTrait;
/**
* The database table used by the model.
*
* @var string
*/
protected $table = 'users';
When you add a new file, you need to run this command to rebuild the class map:
Chapter 4: Building A Blog Application 192
composer dump-autoload
Good job! Youve installed the Entrust package for Laravel 5.2!
The official Entrust package doesnt support Laravel 5.2 yet. We have to install a different branch
of Entrust to make it work properly. When the official Entrust package is updated, you may use the
official version (check the next section).
In order to install Entrust for Laravel 5.2, find the require section in your composer.json file, add
this line:
"zizaco/entrust": "dev-laravel-5-2@dev"
"require": {
"php": ">=5.5.9",
"laravel/framework": "5.2.*",
"laravelcollective/html": "5.2.*",
"zizaco/entrust": "dev-laravel-5-2@dev"
},
Add above:
"repositories": [
{
"type": "vcs",
"url": "https://github.com/hiendv/entrust"
}
],
'Zizaco\Entrust\EntrustServiceProvider',
If you are going to use Middleware (requires Laravel 5.1+), find routeMiddleware array in
app/Http/Kernel.php and add:
Run this command to create a entrust.php file, which can be found in the config directory.
You may use this file to customize table names and model namespaces.
Entrust need some database tables to work. Run this command to generate the migrations:
use Zizaco\Entrust\EntrustRole;
Create a new file called Permission.php, place it inside the app directory.
use Zizaco\Entrust\EntrustPermission;
<?php
namespace App;
<?php
namespace App;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Zizaco\Entrust\Traits\EntrustUserTrait;
Chapter 4: Building A Blog Application 195
use EntrustUserTrait;
This is Entrust trait. When you add it to the User model, you can use the following methods: roles(),
hasRole($name), can($permission), and ability($roles, $permissions, $options).
You should have something like this:
<?php
namespace App;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Zizaco\Entrust\Traits\EntrustUserTrait;
/**
* The database table used by the model.
*
* @var string
*/
protected $table = 'users';
When you add a new file, you need to run this command to rebuild the class map:
Chapter 4: Building A Blog Application 196
composer dump-autoload
Good job! Youve installed the Entrust package for Laravel 5.2!
In order to install Entrust, we just need to add this line to the composer.json file:
"zizaco/entrust": "dev-laravel-5"
"require": {
"php": ">=5.5.9",
"laravel/framework": "5.1.*",
"laravelcollective/html": "5.1.*",
"zizaco/entrust": "dev-laravel-5"
},
Installing Entrust
Now, open the config/app.php file and find the providers array, add:
Chapter 4: Building A Blog Application 197
'Zizaco\Entrust\EntrustServiceProvider',
If you are going to use Middleware (requires Laravel 5.1+), find routeMiddleware array in
app/Http/Kernel.php and add:
Run this command to create a entrust.php file, which can be found in the config directory.
You may use this file to customize table names and model namespaces.
Entrust need some database tables to work. Run this command to generate the migrations:
use Zizaco\Entrust\EntrustRole;
Create a new file called Permission.php, place it inside the app directory.
use Zizaco\Entrust\EntrustPermission;
<?php
namespace App;
// ...
<?php
namespace App;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Zizaco\Entrust\Traits\EntrustUserTrait;
use EntrustUserTrait;
This is Entrust trait. When you add it to the User model, you can use the following methods: roles(),
hasRole($name), can($permission), and ability($roles, $permissions, $options).
You should have something like this:
<?php
namespace App;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
use Zizaco\Entrust\Traits\EntrustUserTrait;
/**
* The database table used by the model.
*
* @var string
*/
protected $table = 'users';
When you add a new file, you need to run this command to rebuild the class map:
composer dump-autoload
Create a new roles directory, place it inside the views/backend directory. Then create a new view
called create:
@extends('master')
@section('title', 'Create A New Role')
@section('content')
<div class="container col-md-8 col-md-offset-2">
<div class="well well bs-component">
@if (session('status'))
<div class="alert alert-success">
{{ session('status') }}
</div>
@endif
<fieldset>
<legend>Create a new role</legend>
<div class="form-group">
<label for="name" class="col-lg-2 control-label">Name</l\
abel>
<div class="col-lg-10">
<input type="text" class="form-control" id="name" na\
me="name">
</div>
</div>
<div class="form-group">
<label for="display_name" class="col-lg-2 control-label"\
Chapter 4: Building A Blog Application 202
>Display Name</label>
<div class="col-lg-10">
<input type="display_name" class="form-control" id="\
display_name" name="display_name">
</div>
</div>
<div class="form-group">
<label for="description" class="col-lg-2 control-label">\
Description</label>
<div class="col-lg-10">
<textarea class="form-control" rows="3" id="descript\
ion" name="description"></textarea>
</div>
</div>
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<button type="reset" class="btn btn-default">Cancel<\
/button>
<button type="submit" class="btn btn-primary">Submit\
</button>
</div>
</div>
</fieldset>
</form>
</div>
</div>
@endsection
Chapter 4: Building A Blog Application 203
$role->save();
created!');
}
We use RoleFormRequest here to validate the form, but we dont have the request file yet. Lets
create it:
Update to:
The Display Name and Description fields are optional. We only need to require users to enter the
roles name.
Be sure that you have told Laravel that you want to use Role and RoleFormRequest in the
RolesController:
Chapter 4: Building A Blog Application 205
use App\Role;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Http\Requests\RoleFormRequest;
To view all roles, update the index action of our RolesController as follows:
@extends('master')
@section('title', 'All roles')
@section('content')
</tr>
@endforeach
</tbody>
</table>
@endif
</div>
</div>
@endsection
Role list
Route::get('users/{id?}/edit', 'UsersController@edit');
Route::post('users/{id?}/edit','UsersController@update');
All we need to do is find a correct user using the user id and list all the roles for users to select.
The $selectedRoles is an array that holds the current roles IDs of users.
As you see, we use the Role model here. Dont forget to add this line at the top of the UsersController:
use App\Role;
@extends('master')
@section('name', 'Edit a user')
@section('content')
<div class="container col-md-6 col-md-offset-3">
<div class="well well bs-component">
@if (session('status'))
<div class="alert alert-success">
{{ session('status') }}
</div>
@endif
Chapter 4: Building A Blog Application 210
<fieldset>
<legend>Edit user</legend>
<div class="form-group">
<label for="name" class="col-lg-2 control-label">Name</l\
abel>
<div class="col-lg-10">
<input type="text" class="form-control" id="name" pl\
aceholder="Name" name="name"
value="{{ $user->name }}">
</div>
</div>
<div class="form-group">
<label for="email" class="col-lg-2 control-label">Email<\
/label>
<div class="col-lg-10">
<input type="email" class="form-control" id="email" \
placeholder="Email" name="email"
value="{{ $user->email }}">
</div>
</div>
<div class="form-group">
<label for="select" class="col-lg-2 control-label">Role<\
/label>
<div class="col-lg-10">
<select class="form-control" id="role" name="role[]"\
multiple>
@foreach($roles as $role)
<option value="{!! $role->id !!}" @if(in_ar\
ray($role->id, $selectedRoles))
selected="selected" @endif >{!! $rol\
e->display_name !!}
</option>
@endforeach
</select>
</div>
Chapter 4: Building A Blog Application 211
</div>
<div class="form-group">
<label for="password" class="col-lg-2 control-label">Pas\
sword</label>
<div class="col-lg-10">
<input type="password" class="form-control" name="pa\
ssword">
</div>
</div>
<div class="form-group">
<label for="password" class="col-lg-2 control-label">Con\
firm password</label>
<div class="col-lg-10">
<input type="password" class="form-control" name="pa\
ssword_confirmation">
</div>
</div>
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<button type="reset" class="btn btn-default">Cancel<\
/button>
<button type="submit" class="btn btn-primary">Submit\
</button>
</div>
</div>
</fieldset>
</form>
</div>
</div>
@endsection
This will display a multiple select box for us. We use @foreach to iterate over $roles and display the
select options.
To display which option is selected, we use in_array function to check if $selectedRoles array
contains the roles id.
Save the changes and go to http://homestead.app/admin/users. Click on the name of a user that you
want to edit.
Chapter 4: Building A Blog Application 213
If you click the Submit button now, nothing will happen. We have to edit the update action of
UsersController to save data to our database:
Chapter 4: Building A Blog Application 214
We use users id to find the user and then save the changes to the database using $user->save()
method.
Notice how we handle the password:
$password = $request->get('password');
if($password != "") {
$user->password = Hash::make($password);
}
First, we check if the password is empty. We only save the password when users enter a new one,
using:
$user->password = Hash::make($password);
This will create a hashed password. Before saving a password to the database, remember that you
must hash it using the Hash::make() method.
For more information, visit:
http://laravel.com/docs/master/hashing#introduction
Well need to include the Hash facade and UserEditFormRequest as well. Find:
Add above:
Chapter 4: Building A Blog Application 215
use App\Http\Requests\UserEditFormRequest;
use Illuminate\Support\Facades\Hash;
$user->saveRoles($request->get('role'));
Unfortunately, Entrust doesnt have any method to automatically sync (attach and detach) multiple
roles. Therefore, we have to create a new saveRoles method to handle this scenario:
Open the User.php model, add:
Basically, this method will retrieve the $roles array, which contains roles ID, and attach the
appropriate roles to the user. If there is no role, it will detach the role from the user.
As always, generate the UserEditFormRequest by running this command:
<?php
namespace App\Http\Requests;
use App\Http\Requests\Request;
Edit a user
As you see, there is no filter here, everyone can access the admin area.
There are many ways to restrict access, but the easiest way is using the Auth facade:
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class Manager
{
public function handle($request, Closure $next)
{
if(!Auth::check()) {
return redirect('users/login');
} else {
$user = Auth::user();
if($user->hasRole('manager'))
{
return $next($request);
} else {
return redirect('/home');
}
}
}
}
use Illuminate\Support\Facades\Auth;
Then we use Auth:check() method to check if the user is logged in. If not, then the user is redirected
to the login page.
Chapter 4: Building A Blog Application 219
if(!Auth::check()) {
return redirect('users/login');
} else {
Otherwise, we use Auth::user() method to retrieve the authenticated user. This way, we can check
if the user has the manager role. If not, the user is redirected back to the home page.
$user = Auth::user();
if($user->hasRole('manager'))
{
return $next($request);
} else {
return redirect('/home');
}
Now, try to access the admin area to test our Manager middleware. If you dont sign in and youre
not a manager, you cant access any routes of the admin route group.
Lets move onto creating the admin home page now so that we can access the admin area easily.
Update our routes.php file, add this route into the admin route group:
Route::get('/', 'PagesController@home');
Remove all the default actions and update the Admin/PagesController as follows:
Chapter 4: Building A Blog Application 221
<?php
namespace App\Http\Controllers\Admin;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
@extends('master')
@section('title', 'Admin Control Panel')
@section('content')
<div class="container">
<div class="row banner">
<div class="col-md-12">
<div class="list-group">
<div class="list-group-item">
<div class="row-action-primary">
<i class="mdi-social-person"></i>
</div>
<div class="row-content">
<div class="action-secondary"><i class="mdi-social-i\
nfo"></i></div>
<h4 class="list-group-item-heading">Manage User</h4>
<a href="/admin/users" class="btn btn-default bt\
n-raised">All Users</a>
</div>
</div>
Chapter 4: Building A Blog Application 222
<div class="list-group-separator"></div>
<div class="list-group-item">
<div class="row-action-primary">
<i class="mdi-social-group"></i>
</div>
<div class="row-content">
<div class="action-secondary"><i class="mdi-material\
-info"></i></div>
<h4 class="list-group-item-heading">Manage Roles</h4>
<a href="/admin/roles" class="btn btn-default btn-ra\
ised">All Roles</a>
<a href="/admin/roles/create" class="btn btn-primary\
btn-raised">Create A Role</a>
</div>
</div>
<div class="list-group-separator"></div>
<div class="list-group-item">
<div class="row-action-primary">
<i class="mdi-editor-border-color"></i>
</div>
<div class="row-content">
<div class="action-secondary"><i class="mdi-material\
-info"></i></div>
<h4 class="list-group-item-heading">Manage Posts</h4>
<a href="/admin/posts" class="btn btn-default btn-ra\
ised">All Posts</a>
<a href="/admin/posts/create" class="btn btn-primary\
btn-raised">Create A Post</a>
</div>
</div>
<div class="list-group-separator"></div>
</div>
</div>
</div>
</div>
@endsection
Chapter 4: Building A Blog Application 223
I just add some buttons to access other admin pages here. Feel free to change the layout to your
liking.
One more thing, how about adding a link to our navigation bar to access the admin area easier?
Open the shared/navbar view and find:
@if (Auth::check())
<li><a href="/users/logout">Logout</a></li>
@else
Update to:
Chapter 4: Building A Blog Application 224
@if (Auth::check())
@if(Auth::user()->hasRole('manager'))
<li><a href="/admin">Admin</a></li>
@endif
<li><a href="/users/logout">Logout</a></li>
@else
We can use the hasRole method to check if the user is a manager in views as well.
Admin link
Chapter 4: Building A Blog Application 225
You can also generate the posts migration at the same time by adding the -m option.
Open timestamp_create_posts_table.php, which can be found in the migrations directory. Update
the up method as follows:
Dont forget to run the migrate command to add a new posts table and its columns into our
database:
Route::get('posts', 'PostsController@index');
Route::get('posts/create', 'PostsController@create');
Route::post('posts/create', 'PostsController@store');
Route::get('posts/{id?}/edit', 'PostsController@edit');
Route::post('posts/{id?}/edit','PostsController@update');
Create a new posts folder in the backend directory. Place a new create view there:
@extends('master')
@section('title', 'Create A New Post')
@section('content')
<div class="container col-md-8 col-md-offset-2">
<div class="well well bs-component">
@if (session('status'))
<div class="alert alert-success">
{{ session('status') }}
</div>
@endif
<fieldset>
<legend>Create a new post</legend>
<div class="form-group">
<label for="title" class="col-lg-2 control-label">Title<\
/label>
<div class="col-lg-10">
<input type="text" class="form-control" id="title" p\
laceholder="Title" name="title">
</div>
</div>
Chapter 4: Building A Blog Application 227
<div class="form-group">
<label for="content" class="col-lg-2 control-label">Cont\
ent</label>
<div class="col-lg-10">
<textarea class="form-control" rows="3" id="content"\
name="content"></textarea>
</div>
</div>
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<button type="reset" class="btn btn-default">Cancel<\
/button>
<button type="submit" class="btn btn-primary">Submit\
</button>
</div>
</div>
</fieldset>
</form>
</div>
</div>
@endsection
Chapter 4: Building A Blog Application 228
This will create a new column called name to store categories name.
Next, open the new timestamp_create_category_post_table migration file and modify the up
method:
$table->foreign('category_id')
->references('id')->on('categories')
->onUpdate('cascade')
->onDelete('cascade');
Chapter 4: Building A Blog Application 230
$table->foreign('post_id')
->references('id')->on('posts')
->onUpdate('cascade')
->onDelete('cascade');
});
}
Category_post table
Check your database to make sure that you have all these tables: posts, categories and category_-
post.
Alternatively, you can use Laravel 5 Extended Generators package to generate the pivot table
faster:
Chapter 4: Building A Blog Application 231
https://github.com/laracasts/Laravel-5-Generators-Extended
Great! Now open our Post model and update it to look like this:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
We use $guarded property to make all columns mass assignable, except the id column.
The belongsToMany method is used to let Laravel know that this model has many-to-many relation.
Open our Category model and update it to look like this:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
Route::get('categories', 'CategoriesController@index');
Route::get('categories/create', 'CategoriesController@create');
Route::post('categories/create', 'CategoriesController@store');
Open the newly created CategoriesController and update the create action:
As usual, create a new categories folder inside the backend directory. Put a new create view in the
categories directory:
@extends('master')
@section('title', 'Create A New Category')
@section('content')
<div class="container col-md-8 col-md-offset-2">
<div class="well well bs-component">
@if (session('status'))
<div class="alert alert-success">
{{ session('status') }}
</div>
@endif
Chapter 4: Building A Blog Application 233
<fieldset>
<legend>Create a new category</legend>
<div class="form-group">
<label for="name" class="col-lg-2 control-label">Name</l\
abel>
<div class="col-lg-10">
<input type="text" class="form-control" id="name" na\
me="name">
</div>
</div>
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<button type="reset" class="btn btn-default">Cancel<\
/button>
<button type="submit" class="btn btn-primary">Submit\
</button>
</div>
</div>
</fieldset>
</form>
</div>
</div>
@endsection
Good job! Now open the CategoriesController again, update the store action as follows:
$category->save();
Tell Laravel that you want to use the CategoryFormRequest and the Category model:
use App\Category;
use App\Http\Requests\CategoryFormRequest;
Modify the authorize method and the rules method to look like this:
Save the changes and visit the category form again. Create some categories (News, Laravel,
Announcement, etc.) :
Chapter 4: Building A Blog Application 236
To view all categories, open CategoriesController again, update the index action:
@extends('master')
@section('title', 'All categories')
@section('content')
@endsection
Add below:
<div class="list-group-item">
<div class="row-action-primary">
<i class="mdi-file-folder"></i>
</div>
<div class="row-content">
<div class="action-secondary"><i class="mdi-material-inf\
o"></i></div>
<h4 class="list-group-item-heading">Manage Categories</h\
4>
<a href="/admin/categories" class="btn btn-default btn-r\
aised">All Categories</a>
<a href="/admin/categories/create" class="btn btn-primar\
y btn-raised">New Category</a>
</div>
</div>
<div class="list-group-separator"></div>
Add above:
Chapter 4: Building A Blog Application 240
use App\Category;
use App\Post;
use Illuminate\Support\Str;
<div class="form-group">
<label for="content" class="col-lg-2 control-label">Content</label>
<div class="col-lg-10">
<textarea class="form-control" rows="3" id="content" name="content"></te\
xtarea>
</div>
</div>
<div class="form-group">
<label for="categories" class="col-lg-2 control-label">Categories</label>
<div class="col-lg-10">
<select class="form-control" id="category" name="categories[]" multiple>
@foreach($categories as $category)
<option value="{!! $category->id !!}">
{!! $category->name !!}
</option>
@endforeach
</select>
</div>
</div>
Chapter 4: Building A Blog Application 241
Modify the authorize method and the rules method of the PostFormRequest to look like this:
Chapter 4: Building A Blog Application 242
use App\Http\Requests\PostFormRequest;
$post->save();
$post->categories()->sync($request->get('categories'));
To create the posts slug, we can use Str::slug method to automatically generate a friendly slug from
the given posts title.
After saving the post to the database using $post->save, we can use:
Chapter 4: Building A Blog Application 243
$post->categories()->sync($request->get('categories'));
Route::get('posts', 'PostsController@index');
@extends('master')
@section('title', 'All posts')
@section('content')
</tr>
</thead>
<tbody>
@foreach($posts as $post)
Chapter 4: Building A Blog Application 245
<tr>
<td>{!! $post->id !!}</td>
<td>
<a href="#">{!! $post->title !!} </a>
</td>
<td>{!! $post->slug !!}</td>
<td>{!! $post->created_at !!}</td>
<td>{!! $post->updated_at !!}</td>
</tr>
@endforeach
</tbody>
</table>
@endif
</div>
</div>
@endsection
Edit a post
We also have defined these routes:
Route::get('posts/{id?}/edit', 'PostsController@edit');
Route::post('posts/{id?}/edit','PostsController@update');
@extends('master')
@section('title', 'Edit A Post')
@section('content')
<div class="container col-md-8 col-md-offset-2">
<div class="well well bs-component">
@if (session('status'))
<div class="alert alert-success">
{{ session('status') }}
</div>
@endif
<fieldset>
<legend>Edit a post</legend>
<div class="form-group">
<label for="title" class="col-lg-2 control-label">Title<\
/label>
<div class="col-lg-10">
<input type="text" class="form-control" id="title" p\
laceholder="Title" name="title" value="{{ $post->title }}">
</div>
</div>
<div class="form-group">
<label for="content" class="col-lg-2 control-label">Cont\
ent</label>
<div class="col-lg-10">
<textarea class="form-control" rows="3" id="content"\
name="content">{!! $post->content !!}</textarea>
</div>
</div>
<div class="form-group">
<label for="select" class="col-lg-2 control-label">Categ\
Chapter 4: Building A Blog Application 247
ories</label>
<div class="col-lg-10">
<select class="form-control" id="categories" name="c\
ategories[]" multiple>
@foreach($categories as $category)
<option value="{!! $category->id !!}" @if(i\
n_array($category->id, $selectedCategories))
selected="selected" @endif >{!! $cat\
egory->name !!}
</option>
@endforeach
</select>
</div>
</div>
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<button type="reset" class="btn btn-default">Cancel<\
/button>
<button type="submit" class="btn btn-primary">Submit\
</button>
</div>
</div>
</fieldset>
</form>
</div>
</div>
@endsection
After creating the form, youll need to modify the posts/index view to add links to the posts.
Find:
Edit to:
Go to http://homestead.app/admin/posts and click on the post title, you should be able to see a post
edit form:
Chapter 4: Building A Blog Application 248
Modify the authorize method and the rules method to look like this:
Chapter 4: Building A Blog Application 249
Add above:
use App\Http\Requests\PostEditFormRequest;
Finally, update the update method to save the changes to our database:
$post->save();
$post->categories()->sync($request->get('categories'));
Instead of creating a new saveCategories method (similar to the saveRoles method), we can sync
the categories like this:
Chapter 4: Building A Blog Application 250
$post->categories()->sync($request->get('categories'));
Route::get('/blog', 'BlogController@index');
Tell Laravel that you want to use the Post model in this controller. Add above:
use App\Post;
Create a new index view at views/blog directory. The following are the contents of the views/blog/in-
dex.blade.php file:
@extends('master')
@section('title', 'Blog')
@section('content')
@if (session('status'))
<div class="alert alert-success">
{{ session('status') }}
</div>
@endif
Chapter 4: Building A Blog Application 252
@if ($posts->isEmpty())
<p> There is no post.</p>
@else
@foreach ($posts as $post)
<div class="panel panel-default">
<div class="panel-heading">{!! $post->title !!}</div>
<div class="panel-body">
{!! mb_substr($post->content,0,500) !!}
</div>
</div>
@endforeach
@endif
</div>
@endsection
We use mb_substr (Multibyte String) function to display only 500 characters of the post.
If you want to learn more about the function, visit:
http://php.net/manual/en/function.mb-substr.php
We should add a blog link to our navigation bar to access the blog page faster. Open shared/-
navbar.blade.php and find:
<li><a href="/about">About</a></li>
Add above:
<li><a href="/blog">Blog</a></li>
Blog page
Route::get('/blog/{slug?}', 'BlogController@show');
Before updating the show method, lets think about how we can implement the blog post comment
feature.
Chapter 4: Building A Blog Application 254
Note: I assume that youve created a Comment model. If not, please read Chapter 3 to
know how to implement the comment feature.
Normally, we have to create a different Comment model (PostComment, for example) to list a
posts comments. That means we have two columns: comments and postcomments. Fortunately,
by defining Polymorphic Relations, we can store comments for our tickets and for our posts using
only a single comments table!
} else {
Schema::table('comments', function (Blueprint $table) {
$table->string('post_type')->nullable();
});
}
}
We check if the comments table has the post_type column. If not, we add the post_type column
into the table.
Dont forget to run the migrate command:
Post_type column
Its time to build the Polymorphic relationship. Open the Comment model, update it as follows:
Chapter 4: Building A Blog Application 256
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
The comments() method will get all of the posts comments . Done! Youve defined Polymorphic
relations.
Now, open BlogController and update the show method:
@extends('master')
@section('title', 'View a post')
@section('content')
@foreach($comments as $comment)
<div class="well well bs-component">
<div class="content">
{!! $comment->content !!}
</div>
</div>
@endforeach
@foreach($errors->all() as $error)
<p class="alert alert-danger">{{ $error }}</p>
@endforeach
@if(session('status'))
<div class="alert alert-success">
{{ session('status') }}
</div>
@endif
<fieldset>
<legend>Comment</legend>
Chapter 4: Building A Blog Application 259
<div class="form-group">
<div class="col-lg-12">
<textarea class="form-control" rows="3" id="cont\
ent" name="content"></textarea>
</div>
</div>
<div class="form-group">
<div class="col-lg-10 col-lg-offset-2">
<button type="reset" class="btn btn-default">Can\
cel</button>
<button type="submit" class="btn btn-primary">Po\
st</button>
</div>
</div>
</fieldset>
</form>
</div>
</div>
@endsection
Notice that weve added a new hidden field called post_type. Because this is the posts comment,
the value of the field is: AppPost (class name).
Open CommentsController and find:
Add below:
We add a new hidden field called post_type, which has the AppTicket value, to let Laravel know
that the comments of this view belong to the Ticket model.
One more thing to do, open the blog/index view and find:
Modify to:
Now, go to your browser and view a post. Try to post a comment as well.
Chapter 4: Building A Blog Application 261
Comments table
Chapter 4: Building A Blog Application 262
As you see, even though the comments have the same post_id (which is 2), their post_type values
are different. The ORM uses the post_type column to determine which model is related to the
comments.
Its a bit confusing. However, if you know how to use Polymorphic Relations, you will gain many
benefits.
This will create a class called UserTableSeeder, which is placed in database/seeds directory.
],
[
'name' => 'Lisa',
'email' => str_random(12).'@email.com',
'password' => bcrypt('yourPassword'),
'created_at' => new DateTime,
'updated_at' => new DateTime,
Chapter 4: Building A Blog Application 263
],
]);
}
Within the run method, we use database query builder to create dummy user data. Keep in mind
that we can also load data from a JSON or CSV file.
Instead of using the Hash facade to hash the password, you can also use the bcrypt() helper function
to do that.
Read more about Database Query Builder here:
http://laravel.com/docs/master/queries
You may also want to try Faker, which is a popular PHP package that helps to create fake data
effectively.
https://github.com/fzaninotto/Faker
After writing the seeder class, open database/seeds/DatabaseSeeder.php.
// $this->call('UserTableSeeder');
Model::reguard();
}
Normally, we would create many seeder classes to seed different dummy data. For example,
UserTableSeeder is used to create fake users, PostTableSeeder is used to create dummy posts, etc.
We use the DatabaseSeeder file to control the order of seeder classes. In this case, we only have one
UserTableSeeder class, so lets write like this:
$this->call('UserTableSeeder');
Model::reguard();
}
This will execute the run method of the UserTableSeed class and insert data into our database.
Now check your database or visit http://homestead.app/admin/users, there are some new users:
New users
Seeding is very useful. You may try to use this feature to create posts, tickets and other data to test
your application!
Chapter 4: Building A Blog Application 265
Localization
You can easily translate strings to multiple languages using Laravel localization feature.
All language files are stored in the resources/lang directory.
By default, there is an en (English) directory, which contains English strings. If you want to support
other languages, create a new directory at the same level as the en directory. Please note that all
language directories should be named using ISO 639-1 Code.
Read more about ISO 639-1 Code here:
http://www.loc.gov/standards/iso639-2/php/code_list.php
Open en/passwords.php file:
<?php
return [
'password' => 'Passwords must be at least six characters and match the confi\
rmation.',
'user' => "We can't find a user with that e-mail address.",
'token' => 'This password reset token is invalid.',
'sent' => 'We have e-mailed your password reset link!',
'reset' => 'Your password has been reset!',
];
As you see, a language file simply returns an array that contains translated strings.
You can change the default language by editing this:
<?php
return [
];
Change to:
The trans helper function is used to retrieve lines from language files:
main is the name of the language file (main.php). subtitle is the key of the language line.
As you notice, we may use the localization feature to manage strings as well. For example, put all
your applications strings into the main.php file; when you want to edit a string, you can find it
easily.
Dont forget to read the docs to learn more about localization:
http://laravel.com/docs/master/localization
Chapter 4: Building A Blog Application 268
Chapter 4 Summary
Congratulations! Youve built a complete blog application!
Our application is not perfect yet, but you may use it as a starter template and apply some concepts
that youve known to build a larger application.
Towards the end of this chapter, lets review what we have learned:
Youve known how to authenticate users and add login throttling to your app.
You now understand more about routes and route group.
Using Middleware, you can handle requests/responses effectively.
Many Laravel applications are using Entrust, its one of the best packages to manage roles and
permissions. We only use the roles feature in this book. Try to create some permissions to
secure your apps better.
Understanding Many-to-Many Relations and Polymorphic Relations is hard at first, but youll
gain many benefits later.
Now you can be able to seed your database! Seeding is easy. Right?
The Laravel localization feature is simple, but its very helpful and powerful. Try to use it in
all your applications to manage all the strings.
Remember that, this is just a beginning, there is still so much more to learn.
Hopefully, you will have a successful application someday! Enjoy the journey!
If you wish to learn more about Laravel, check our Laravel 5 Cookbook out!
Note: Ill be updating all chapters to fix some mistakes in both code and grammar. Also,
more sections will be added later. If you would like to give feedback, report bugs, or ask
any questions, please email us at support@learninglaravel.net. Thank you.
Chapter 5: Deploying Our Laravel
Applications
Currently, were just working locally on our personal computers. We will have to deploy our
applications to some hosting services or servers so that everyone can access it. There are many
ways to make your application visible to the rest of the world!
In this chapter, I will show you how to deploy your Laravel applications using these popular methods:
If you find out some better solutions, feel free to contact us. Ill update the book to talk about other
approaches.
To deploy a Laravel application, you may have to follow these steps:
269
Chapter 5: Deploying Our Laravel Applications 270
/home/content/learninglaravel/public_html
You will need to create a directory on the same level as the public_html directory. This direc-
tory will hold your Laravel application. Because its on the same level as your public_html
directory, others cannot access it. This makes the application more secure.
Upload your Laravel application to the new directory using an FTP client (such as Filezilla,
Transmit, CuteFTP, etc.), except the public folder.
Upload the public folder to the public_html directory.
Good job! Now open the index.php file and change two paths:
require __DIR__.'/../bootstrap/autoload.php';
and
Last step, go to the public_html directory and modify the .htaccess file (If you dont have one,
create a new file):
RewriteEngine On
RewriteCond %{REQUEST_URI} !^public
RewriteRule ^(.*)$ public/$1 [L]
Well done, now its time to visit your website URL! (www.yourdomain.com). You should see the
Laravel welcome screen.
Chapter 5: Deploying Our Laravel Applications 271
Note: Please note that your application may not work properly on shared hosting and
there is a security risk. Laravel is not designed to work on a shared host.
DigitalOcean pricing
DigitalOcean is also my best favorite hosting solution. The performance is really amazing!
In this section, Ill show you how to install Laravel with Nginx on a Ubuntu 14.04 LTS VPS. (Ubuntu
14.04 Long Term Support Virtual Private Server)
Why do I choose Ubuntu 14.04? There are some newer versions of Ubuntu (14.10, 15.04, etc.), but
the 14.04 is an LTS version, that means we will receive updates and support for at least five years.
Alternatively, you can use Laravel Forge to install the VPS and configure everything for you.
However, you will have to pay $10/month.
Note: You will need to provide your credit card information or Paypal to activate your
account.
After your account has been activated. You will need to create a droplet, which is a cloud server.
Click on the Create Droplet button or go to:
https://cloud.digitalocean.com/droplets/new
Create a droplet
Great! Now you can access the new server via Terminal or Git Bash by using this command:
ssh root@128.199.206.121
The first time you login, it will ask you to change the password. Enter the current Unix password
again, and then enter your new password to change it.
Finally, run this command to check and update all current packages to the latest version:
Install Nginx
Install Nginx is very simple, you just need to run this command:
Chapter 5: Deploying Our Laravel Applications 275
Enter y and hit Return (Enter on Windows) if it ask you to confirm anything.
Done! You can now visit your Nginx server via the IP address:
http://128.199.206.121
Your website
To get started, we need to install MySQL to store our data. Run this command:
Chapter 5: Deploying Our Laravel Applications 276
Say Y to everything. If youre asked to enter a new password for the MySQL root user, give it a
password.
MySQL password
Next, you need to tell MySQL to configure the databases for you and run a security script to ensure
that your settings are safe:
sudo mysql_install_db
sudo mysql_secure_installation
All done! If you've completed all of the above steps, your MySQL
installation should now be secure.
Good job! Youve installed MySQL. We will install PHP in the next section.
;cgi.fix_pathinfo=1
You can use Ctrl + V to quickly move to the next page. Uncomment it and change it to 0
cgi.fix_pathinfo=0
Once complete, press Ctrl + X, and say Y to save the file. Press Return (or Enter) to exit.
By doing this, you tell PHP that you dont want PHP to look for the nearest file if it cannot find
your requested file. if you dont make the change, there is a possible security risk.
After that, we need to edit the server block (aka virtual hosts) file. Open it:
Find:
root /usr/share/nginx/html;
This is the path to your Laravel application, we dont have the Laravel application yet, but lets
change it to:
Chapter 5: Deploying Our Laravel Applications 278
root /var/www/learninglaravel.net/html;
Find:
Change to:
Find:
location / {
# First attempt to serve request as file, then
# as directory, then fall back to displaying a 404.
try_files $uri $uri/ =404;
# Uncomment to enable naxsi on this location
# include /etc/nginx/naxsi.rules
}
Add below:
location ~ \.php$ {
try_files $uri /index.php =404;
fastcgi_pass unix:/var/run/php5-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
<html>
<head>
<title>Learning Laravel</title>
</head>
<body>
<h1>Learning Laravel test page.</h1>
</body>
</html>
Now when you visit your website via its IP address, you should see:
Chapter 5: Deploying Our Laravel Applications 280
Your website
Install Laravel
Now that we have everything in order, we will be going to install Composer and use it to download
Laravel Installer!
If youre installing Laravel on 512MB droplets, you must add a swapfile to Ubuntu to prevent it from
running out of memory.
export PATH="$PATH:~/.composer/vendor/bin"
source ~/.bashrc
Once finished, were finally at the part that weve been waiting for: Install Laravel!
We will put our Laravel application at /var/www/learninglaravel.net/. Type the following to get
there:
cd /var/www/learninglaravel.net/
This is a pretty standard process. I hope you understand what weve done. If you dont, please read
Chapter 1.
By now, we should have our Laravel app installed at /var/www/learninglaravel.net/laravel.
Once that step is done, we must give the directories proper permissions:
Find:
root /var/www/learninglaravel.net/html;
Change to:
root /var/www/learninglaravel.net/laravel/public;
Restart Nginx:
Possible Errors
If you see this error:
No supported encrypter found. The cipher and / or key length are invalid.
This is a Laravel 5.1 bug. Sometimes, your app doesnt have a correct application key (this key is
generated automatically when installing Laravel)
You need to run these commands to fix this bug:
Chapter 5: Deploying Our Laravel Applications 284
shutdown -h now
Now, go to DigitalOcean Control Panel. Go to your droplet. Click on the Snapshots button to
view the Snapshots section.
Chapter 5: Deploying Our Laravel Applications 285
Take a snapshot
Enter a name and then take a snapshot! You may use this snapshot to restore your VPS later by using
the Restore from Snapshot functionality.
Little tips
Tip 1:
If you have a domain and you want to connect it to your site, open the server block file, and edit
this line:
server_name localhost;
Modify to:
Chapter 5: Deploying Our Laravel Applications 286
server_name yourDomain.com;
Now you can be able to access your site via your domain.
Tip 2:
You can access your server using FTP as well (to upload, download files, etc.), use this information:
User: root
Port: 22
Chapter 5 Summary
Congratulations! You now know how to deploy your Laravel applications!
I hope you like this chapter.
If you wish to learn more about Laravel, check our Laravel 5 Cookbook out!
Thank you again for your support! Have a great time!