What is Laravel?
Laravel is a framework - a set of general purpose components and libraries combined with programming standards that will make the development process easier and much faster.
Why Laravel?
The main advantage of Laravel over other frameworks is its flexibility. Most frameworks force the programmer to work in a certain way. Typically it’s an advantage, but those limitations can significantly slow down your work. Laravel is using a slightly different approach. Instead of forcing a style it’s only suggesting it. This way it combines the advantages of standardization (clean code, easy sharing project with other developers) with the possibility of adding advanced functionalities.
Popularity
At the time this article was written (June 2016) Laravel was one of the most popular frameworks (based on data provided by HotFrameworks). Laravel is 8th in general ranking and 1st on the rank of PHP based frameworks, having over 23 thousand stars on GitHub. As a comparison, CodeIgniter is on the 2nd place with 12 thousand stars.
Laravel - let’s begin
Documentation
As with every new piece of technology, we should start learning Laravel by reading the documentation. Right now Laravel 5.2 is the stable version, so let’s start with reading its official website.
Laravel’s documentation is neatly structured, and different documents match various versions of Laravel. It’s worth mentioning that sometimes it’s a good idea to look into older versions of the documentation. As I said before, Laravel is very flexible so that you can do the same thing in multiple ways. When standard changes documentation does as well, but sometimes it’s just better to use “the old way” if it fits better your project.
First Steps
INSTALLATION
The very first thing you need to do is an installation of PHP (with all required extensions) and MySQL. A complete list can be found here. Details of this process depend on your OS and can be found in its documentation.
The second step is an installation of Composer (if you don't know Composer and how to use it, take a look at our article about it). Particulars of this process can be found here.
When we have everything we need, it's time to install Laravel itself. This can be done in two ways - by using Composer or with Laravel installer. Since we already installed Composer, let's make a good use of it and run following command:
composer create-project --prefer-dist laravel/laravel project-name
ARTISAN VS. HOMESTEAD
One of the first questions we have to ask ourselves is the choice of a development server. Laravel’s documentation suggest the use of Homestead, but I don’t agree with that. Homestead is a good long term solution, but it requires much longer configuration time. After it’s done creating new servers is the matter of seconds but before that… let’s just stick with the alternative solution: Artisan. As you will find out in further parts of this article, Artisan is going to be our primary tool in work with Laravel. One of its features is launching a server. Let’s do it now - the command is:
./artisan serve
That’s all, we have a running server. If you want to stop it, just stop Artisan using standard Unix Ctrl + C shortcut.
FOLDER STRUCTURE
As I mentioned, Laravel is very flexible - it’s clearly visible when you consider its ability to create a custom folder structure. Almost everything can be located anywhere we want. Laravel has a pre-created structure, but it's a good idea to expand it slightly before we start working on our project. Let’s have a look at how our folder structure looks.
The main folder contains following subdirectories:
- app this is the heart of our application, the majority of our code will be placed here;
- Console - this folder contains our console commands and kernel where we register them;
- Events - this is where our events are stored;
- Exceptions - this is where we create our Exceptions. This directory also contains a file named “handler.php” which is responsible for the global handling of exceptions. If you want to handle exceptions on your own, I suggest creating a subfolder called Handlers and filling it with files that implements Illuminate\Contracts\Debug\ExceptionHandler interface;
- HTTP - everything related to accessing our application from the web goes here.
~Controllers - contains controllers used by our app;
~Middleware - includes decorator classes that can modify the Request before it’s passed to the controller as well as Response before it’s sent to the user;
~Requests - contains files responsible for automated validation of requests;
~routes.php - this file contains our routing.
- Jobs - this folder contains “delayed jobs” that can be done any time in the future;
- Listeners - this is where event handling will happen. We place our listeners and subscribers here;
- Policies - we put policies used for managing user permissions here;
- Providers - contains providers - classes responsible for loading and management of our application;
- Model - I would suggest creating this folder for storing our models. Laravel suggests to keep them in the app folder, but when our application grows bigger, it will become very messy. It’s, therefore, advisable to abuse Laravel’s flexibility and keep it clean from the beginning;
- Contracts - another folder we have to create. This time, it’s based on Laravel’s programming style, where you create interfaces (called Contracts) that will group our applications functionalities;
- Services - it’s a good Idea to split our application into smaller tasks. The service-based approach will not only make our code easier to read, but also will make future conservation less painful.
- bootstrap - contains Laravel’s initialization files. We can use them to change kernels’ locations;
- config - this is where our application configuration is placed;
- database - here we put our migrations, seeds, and factories for our database;
- factories - contains scripts used for generating random objects of our class;
- migrations - includes migrations (the definitions of tables in a database) and changes they are undergoing with each update;
- seeds - similar to factories, but instead of creating random entities it creates the ones that were predesigned by the programmer. Useful both for testing and deployment of our application.
- public - this is a special folder that contains files that are directly available from the web;
- .htacces and index.php - both are files that define our application’s entry point;
- packages - if one of installed third-party packages requires publicized files (e.g., its javascript files), those are placed here after using the following command: ./artisan vendor:publish.
- resources - this is where we put our resources;
- assets - it’s a usual place for storing our CSS and JS files as well as other assets we have;
- lang - this folder contains translations. Each subfolder’s name is connected with language’s code (e.g., pl, en, de, etc.);
- views - contains all of our apps’ views;
~errors - holds views that are automatically shown when an error occurs.
- storage - this is where our application is supposed to store its data. Make sure to give the app write permission to this folder;
- app - this directory is designed for our use. Since we have write access here, we can use it to store things such as uploaded files. I would suggest to split it into subfolders based on purpose of the stored data;
~app/public - I would recommend saving here everything you would like to be public to the web. You can then make a symlink to this folder from public/storage like this:
ln -s storage/app/public public/storage
This way our public folder is safe with no write permissions. But, we still can create files that are going to be available on the web.
- framework - this folder is dedicated for Laravel’s dynamically generated files.
~Cache - contains applications cache;
~Sessions - contains files that store session data;
~views - compiled views;
- logs - this folder contains application’s logs;
- … - some packets may create their folders here (e.g., “debugbar”).
- tests - this is where we are supposed to place unit tests;
- vendor - this is where third party packets are installed.
CONFIGURATION
Since we have our Laravel installed, and we prepared our folder structure, it’s time for setting. In most cases, we can stick with default values, unless we want to use some of more advanced features. Most options are well documented, so let’s have a look at them.
.env
The first step in every configuration is a preparation of .env file. This is the most important config file, as it contains all our credentials and server specific configs as opposed to application-specific ones stored in “config” directory.
- APP_ENV - this value defines environment used on the server. It can have two different values: local that prepares the application for testing on the development server, and production that will fully optimize the application for the mass usage in production;
- APP_DEBUG - this field determines whether debugging tools will be on or not. I would suggest to keep it in sync with APP_ENV, where if APP_ENV=production then APP_DEBUG=false, otherwise APP_DEBUG=true
- APP_KEY - this is a random key used in the process of generating and verifying passwords. If you ever change this value after the initial setup, it will cause all passwords generated by Laravel to be no longer valid so that they will require regenerating. This field is filled automatically during the process of installing Laravel. If you want to change it use following command ./artisan key:generate ;
- APP_URL - this area should contain your application’s address. It’s used to create paths from links and assets;
- DB_… - these six fields are used to configure a connection to your database. Most of the fields are self-explanatory. The only exception is “DB_CONNECTION”, where for now we should write “mysql”. Details will be explained in the “database.php” section of this article.
- CACHE_DRIVER - this field will be described in “cache.php” part, for now, leave “file” in it;
- SESSION_DRIVER - this field will be explained in “session.php” section, for now, leave “file” in it as well;
- QUEUE_DRIVER - this field will be explained in “queue.php” part, for now, leave “sync” in it;
- REDIS_… - this field will be explained later. For now, leave it as it is (we won’t be using redis in this article);
- MAIL_… this area will be described in “mail.php” section. Set MAIL_DRIVER to “smtp” and MAIL_ENCRIPTION to “tls”. Other fields are self-explanatory. You should check your port number in the mail provider - for instance, in Gmail, it’s 587 as mentioned here.
CONFIG/APP.PHP
As you can see, a lot of fields in this file contain an env() function. It loads the value for the field from already mentioned .env file. The first parameter of this function is the name of area and second is the default value (in case this field does not exist in .env file). I am going to skip fields that I already described.
- timezone - sets the default timezone for our application. Full list of timezones can be found here;
- Locale - sets the two-letter code of language that will be used as default in our application. The full list can be found here in “639-1” column. For English, it's “en”;
- fallback_locale - this is the language that should be used when ours is not available for certain translation. I suggest setting this field to “en” since most third party software supports English, and most people speak that language, so it's the best possible choice for a fallback language;
- cipher - should be set to “AES-256-CBC”;
- log - decides how we should store log files. Possible values include single (which means store everything in one file), daily (that will make one file per day), syslog ( it will use your operating system's log) and error log ( it will use PHP internal logging). I would recommend using “daily”;
- log_max_files - we have to add this field manually (it does not exist by default). It will be used to set the number of files(days) of logs to keep only when “daily” log is selected. On the other hand, the default value will be five.
- log_level - sets how detailed logs should be. I would suggest setting this field like this: 'log_level' => app_env('APP_LOG_LEVEL', 'debug'), This way we will be logging debug messages by default, but we can still use APP_LOG_LEVEL in our .env file to reduce logging on production. Available log level is in order: debug, info, notice, warning, error, critical, alert, emergency;
- providers - this is where we will be adding third party modules to our application. Make sure to keep the format in which those modules are written. In older Laravel versions it was different, and some documentations may still contain old form;
- aliases - this is where we define so-called facades. We won't be making our facades, but you should remember about this field when installing third party modules and its documentation says to include a facade.
CONFIG/AUTH.PHP
- defaults - this field contains the default guard and password provider. Set guard to “web” (to use sessions on our website) or API (to use tokens). On a website we are using sessions so set it to “web”; we leave passwords as “users”;
- guards - this is where we can define more guards. I know no good reason to do it, so just leave it as it is;
- providers - this is where we define our user class that is used by the authentication system. For now, keep it as is.
CONFIG/CACHE.PHP
This file lets you define cache for your application. Caching can greatly improve application’s performance, so let’s see what we have available in Laravel.
Array
This position means that there is no cache at all. Using this driver cached data will be available only during a single call, then they will be lost. I don’t recommend using this as default.
File
Caching in files is already a standard for most frameworks. In Laravel this is the default option, and it’s good for small projects. This is why we will be using it in the rest of this article. Configuration is as simple as setting a folder where cache files will be stored, so let's keep it as “storage/framework/cache”. Don’t forget that we need to write permissions to that directory.
Apc
If File is a solution for small projects, APC is good for small projects with a lot of clients. Advantages of APC is ease of installation and configuration (in fact we don’t need to do anything other than installing APC from PECL) and best performance boost in case of small amount of cached data.
Memcached
If the cache is supposed to do something more than just increasing website performance, then it's a good idea to use third-party software. One of the most popular solutions is Memcached. It's slower than APC, but it contains the advantage of sharing data in case of load balancing solutions. Memcached is useful for storing key-value pairs. Detailed information about Memcached is beyond the scope of this article.
Redis
The last solution on the list (which is similar to Memcached) is Redis. Redis is the best choice if we want to cache complicated structures and objects. What's more, it allows using queues (we will talk about them later).
Before choosing a proper caching mechanism, I would suggest reading more about pros and cons of different solutions. We should also remember that we are not limited to using a single cache system at the same time.
CONFIG/DATABASE.PHP
This file lets us make a more advanced database configuration. Laravel without installing any external packets supports following database solutions: MySQL, pgSQL, SQLite, SQLSRV. Most of the configurations are already prepared, the only exception is SQL SVR, which requires adding one additional section:
'sqlsrv' => array(
'driver' => 'sqlsrv',
'host' => env('DB_HOST', 'localhost'),
'port' => env('DB_PORT', '1433'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'prefix' => '',
),
In this file, we can also select the name of the table used to store migrations, as well as configure our Redis connection.
CONFIG/FILESYSTEMS.PHP
This file enables us to manage filesystems that you are using in your project. Laravel allows you to use a lot of filesystems thanks to a library called Flysystem. Sometimes we want few files to be stored locally and some in the cloud. This combination is also possible with Laravel. The default config lets you store files in “storage/app”, and “storage/app/public" in case of files with public access. Also, Amazon (s3) cloud is available. Let’s do some modifications and swap the s3 disks section with the following code:
's3' => [
'driver' => 's3',
'key' => env('DISK_S3_KEY', ''),
'secret' => env('DISK_S3_SECRET', ''),
'region' => env('DISK_S3_REGION', ''),
'bucket' => env('DISK_S3_BUCKET', ''),
],
'ftp' => [
'driver' => 'ftp',
'host' => env('DISK_FTP_HOST', ''),
'port' => env('DISK_FTP_PORT', 21),
'username' => env('DISK_FTP_USERNAME', ''),
'password' => env('DISK_FTP_PASSWORD', ''),
'root' => env('DISK_FTP_ROOT', ''),
],
This way we can put our credentials in one place (.env file). We will have not only cleaner code but also our keys will be much safer without the risk of accidentally putting them into the repository. We also included the FTP drive. The same way we can add other drives we want (some may need a custom adapter).
CONFIG/MAIL.PHP
This file is responsible for sending emails. We already set all required parameters in .env file. I would also like to add that using SMTP is not the only way of sending emails in Laravel. The alternatives include: send mail script (path to this script we set in its field), mail to use PHP’s mail() function and third-party solutions (mailgun, mandril, amazon ses or sparkpost)
During the development you may set driver to log to save email in log instead of sending the message, or add the following section:
'to' => [
'address' => 'dev@domain.com',
'name' => 'Dev Example'
],
To automatically redirect all emails to target address. Make sure you remove it before deployment.
CONFIG/QUEUE.PHP
This file is responsible for queue system. Queues are a way to do time-consuming jobs “later”. We have a few solutions available:
sync
This is the default and the simplest solution that means “no queues”. Queued jobs are done while the script is running. This is the only solution that doesn’t need any extra infrastructure. We can leave it if we are not planning to use queues or if queued jobs are going to be short enough.
database
The simplest of queuing methods that will be using our database to store queued jobs. The configuration requires you to select database connection (driver field should be a valid connection name, not the driver name) and table where we will store our jobs. Required migration can be generated using artisan:
./artisan queue:table.
In the case of a database engine, it’s crucial to set the expire field correctly. The expire field is used to prevent processing the same job twice. For this to be true, it should be higher than timeout value used when starting workers.
redis
The configuration of redis is as simple as choosing the connection name and expire value.
beanstalk and sqs
Commercial solutions can be configured by using the correct credentials. As always I suggest using the env() function to store them in .env file.
failed
The last section is used to select a table in our database that should be used to store jobs that failed. The migration can be created using artisan:
./artisan queue:failed-table
CONFIG/SERVICES.PHP
Some third party packets require extra configuration. In most cases, packets will use a file with name matching the packet’s name, but some don’t. Those packages store their config here.
CONFIG/SESSIONS.PHP
This file is responsible for configuring sessions. Lifetime and expire_on_close will point to how to log a session should be stored (in minutes) and if it should be removed after the browser is closed. The driver field will determine where session should be stored:
- file - stored in files placed in a folder selected with files field;
- cookie - sent with each response and returned in each request of a browser (not recommended due to traffic and security issues);
- database - stored in a database that is defined by connection and table fields. Migration can be made using artisan:
./artisan session:table;
- apc - stored in servers’ RAM;
- memcached - stored in memcached server (using config from cache.php file);
- redis - stored in redis server (connection field);
- array - a session is stored only for a single call and lost after that (that’s technically a disabled session system);
Lottery field is used to calculate the chance of clearing outdated session. For example, when it’s set to [2,100] then it will have 2% (2/100) chance that it will activate the session’s garbage collector. Path and domain fields are used to define the parameters of cookie used to identify the session. If you want sessions to work only on https connection, set secure to true. We should keep http_only as is.
CONFIG/VIEW.PHP
This file allows you to add custom paths to views. I would not recommend removing the default path, as most third-party packets will install their views there. The compiled field lets you choose the location of compiled views. I would also not suggest any changes to this field.
Important files
Now we should create a few files that will make our future work much easier.
APP/MODE/MODEL.PHP
<?php
namespace App\Model;
use Illuminate\Database\Eloquent\Model as BaseModel;
class Model extends BaseModel
{
}
You may think that creating a file that does nothing is stupid, but over time if we want to add something to all of our Models, then we can do it using this file. In fact, let’s do it now. Just add this line in our class:
protected $guarded = [];
This one line will let us unlock mass assignment required for example in seeders.
AUTH SYSTEM
It’s almost certain that we will eventually need some form of authentication. So instead of delaying it, let’s do it now. The easiest way is letting Laravel do it for us by using the command:
./artisan make:auth
This will prepare the entire login system, but we’ll have to modify it slightly. The first step is removing the user class (‘app/User.php’) and creating our own that will fit our folder structure (‘app/Model/Auth/User.php’). Also, since Laravel’s functionality is mostly based on interfaces and traits, we don’t need to extend the default user class. We can extend our model class instead. We can even disable and enable parts of functionality by swapping traits. Here is how our User class looks now:
<?php
namespace App\Model\Auth;
use App\Model\Model;
use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Foundation\Auth\Access\Authorizable;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
class User extends Model implements
AuthenticatableContract,
AuthorizableContract,
CanResetPasswordContract
{
use Authenticatable, Authorizable, CanResetPassword;
/**
* The attributes that are mass assignable.
*
* @var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* @var array
*/
protected $hidden = [
'password', 'remember_token',
];
}
Now we need to set our class as user provider by editing config/auth.php file and setting
'model' => App\Model\Auth\User::class
in providers section.
Since we are talking about authentication, we also need a controller for that. Let’s have a look into files that were generated: app/Http/Controllers/Auth/AuthController.php and app/Http/Controllers/Auth/PasswordController.php We will need to make following changes:
- swapping use App\User with use App\Model\Auth\User;
- setting path where we want to redirect users after they log in ($redirectTo);
- deciding whether we want to disallow registration (we can swap AuthenticatesAndRegistersUsers trait with AuthenticatesUsers);
- deciding whether we want to limit login tries (ThrottlesLogins trait, $maxLoginAttempts and $lockoutTime fields).
In routing we already have a line saying Route::auth(); that automatically adds our AuthController. If we check how it’s implemented, we will find that in fact it registers paths to /login, /register, /logout and some /password subpaths. If we want our routes, we can make them in a similar way.
All required views were created in resources/views/auth folder. For now, we will just leave them be, but later you can modify them to fit your websites style.
All the required migrations are ready, we just need to run them like this:
./artisan migrate
Useful packets
We already have a well configured Laravel application, but there are still two packages that we should add before starting development.
LARAVEL-DEBUGBAR
This packet will add a bar on the bottom of our website that will be useful during debugging. Note that this bar will only be visible if debug is turned on.
Installation of this packet is very simple.
- run
composer require barryvdh/laravel-debugbar;
- add
Barryvdh\Debugbar\ServiceProvider::class
in app.php providers section; - add
'Debugbar' => Barryvdh\Debugbar\Facade::class
in app.php aliases section; - run
./artisan vendor:publish --provider="Barryvdh\Debugbar\ServiceProvider"
IDE HELPER
One of the biggest disadvantages of Laravel is its weak autocomplete support. This is because Laravel is very dynamic and will parse most commands when almost all of them have some meaning.
To solve this issue, we can install ide helper that will make a fake Laravel clone, which will be designed in a way that will work fine with autocomplete.
Installation:
- run
composer requires barryvdh/laravel-ide-helper;
- add
Barryvdh\LaravelIdeHelper\IdeHelperServiceProvider::class
in app.php providers section; - run
./artisan ide-helper:generate"
to generate autocomplete for facades (you must run this every time you install a new package that adds a facade); - run
./artisan ide-helper:models"
to generate autocomplete for models (you must run this every time you create or edit one of your models); - run
./artisan ide-helper:meta"
to generate autocomplete for a container (you must run this every time you install new package or register a class in a container).
Summary
In this article together we created a well configured and fully operational base of application powered by Laravel. As you probably saw during our preparations, Laravel is very easy, intuitive and user-friendly. It was hard for me to write something that was not either obvious or already mentioned in documentation, but still, I hope this article helped you to start your work with Laravel.
Useful Links
Navigate the changing IT landscape
Some highlighted content that we want to draw attention to to link to our other resources. It usually contains a link .