This document provides an overview and introduction to Laravel 5, a PHP web application framework. It discusses key Laravel 5 concepts and features such as Eloquent ORM, routing, middleware, contracts, form requests, the IoC container, file drivers, scheduling commands, and the command bus pattern. The document is intended to explain Laravel 5 concepts through code examples and brief explanations.
2. @minusdarren
Introduction
Darren Craig
CTO - @minus40co
โ Built my ๏ฌrst website in 1998
โ Hosted on FortuneCity
โ Developing in PHP for over 10 years
โ Superstar DJ
โฆ in Microsoft Word
(ish)
3. Caveats
โ Code is an example only - not best practiceโฆ
โ โฆor consistent!
โ Mix of basic and advanced ideas
โ Please ask questions!
โ More than one way to skin a cat
5. What is Laravel?
โ PHP Framework
โ V1 was released in 2011
โ Taylor Otwell (@taylorotwell)
โ V5 released in February 2015
โ Laracon - Annual conferences in EU & US
6. Why are you talking about it?
โ Using Laravel since v3
โ Excellent Framework
โ Striving for better & more robust applications
โ Laravel helping lead the charge
โ PSR-4
โ Contracts/Interfaces
โ Command Bus
โ SOLID principles
โ Community - DDD, Testing, Event Sourcing
7. Under the hood
โ Uses Composer (http://getcomposer.org)
โ >= PHP 5.4
โ Leverages lots of Symfony components
โ Artisan CLI
โ Eloquent ORM
9. PHPSpec
โ Testing library
โ Uses โDesign by Speci๏ฌcationโ
class EmailAddressSpec
{
public function it_validates_the_email()
{
$this->shouldThrow('Exception')->during('__construct', ['InvalidEmail.com'])
}
public function it_normalizes_the_address()
{
$this->beConstructedWith('StrangeCASE@EmailAddress.com');
$this->getEmail()->shouldReturn('strangecase@emailaddress.com');
}
}
vendor/bin/phpspec describe EmailAddress
vendor/bin/phpspec run
10. PHPSpec
class EmailAddress
{
private $email;
public function __construct($email)
{
if( !filter_var($email, FILTER_VALIDATE_EMAIL) ) throw new Exception;
$this->email = strtolower($email);
}
public function getEmail()
{
return $this->email;
}
}
17. Routing
โ Routes moved to app/Http/routes.php
โ RESTful routes
โ No namespace necessary!
Route::get(โ/', 'WelcomeController@index');
$router->get(โ/','WelcomeController@index');
Route::get(โฆ);
Route::post(โฆ);
Route::put(โฆ);
Route::patch(โฆ);
Route::delete(โฆ);
18. Routing
โ Route Variables
Route::get('video/{video}', โVideoController@show');
Route::get('/video/{video}/comments/{comment}', 'VideoCommentsController@show');
// VideoController
public function show($videoId) {}
// VideoCommentsController
public function show($videoId, $commendId) {}
โ Resource Routes
Route::resource('video', 'VideoController');
@index
@show
@create
@store
@edit
@update
@delete
19. Routing
โ Implicit Controllers
Route::controller('videos', โVideoController');
class VideoController extends Controller
{
public function getIndex() {} // GET videos
public function postProfile() {} // POST videos/profile
public function anyAction() {} // ANY videos/action
}
20. RouteServiceProvider
class RouteServiceProvider extends ServiceProvider {
protected $namespace = โAppHttpControllers';
public function map(Router $router)
{
$router->group(['namespace' => $this->namespace], function($router)
{
require app_path('Http/routes.php');
});
}
}
21. Route Cache
โ Resolves and caches your routes ๏ฌle
โ Drastically speeds up applications with lots of
routes
php artisan route:cache
23. Eloquent
โ Laravelโs own Active Record implementation
โ Beautifully expressive syntax
โ Allows you to easily query and update your database
โ Has drivers for MySQL, SQLite, Postgres, SQL Server
and Redis out of the box.
โ Lots of packages available for DB support
24. Eloquent
class User extends Model {
public function comments()
{
return $this->hasMany('Comment');
}
}
$user = User::all();
$user = User::find(1);
$user = User::where('name', =, $name)->first();
$user = User::where('age', <, 18)->get();
$user = User::with('comments')->get();
@foreach($user->comments as $comment)
<li>{{ $comment->body }}</li>
@endforeach
25. Eloquent N+1 Problem
// 1 query per comment
$user = User::first();
@foreach($user->comments as $comment)
<li>{{ $comment->body }}</li>
@endforeach
// 1 query total
$user = User::with('comments')->first();
@foreach($user->comments as $comment)
<li>{{ $comment->body }}</li>
@endforeach
28. IoC Container
class UserController
{
public function getProfile()
{
$facebook = new Facebook(['appId' => 123, 'secret' => 'cohaaagan']);
$user = $facebook->getUser();
}
public function getFriends()
{
$facebook = new Facebook(['appId' => 123, 'secret' => 'cohaaagan']);
$friends = $facebook->getFriends();
}
}
29. IoC Container
class FooController
{
private $facebook;
public function __construct()
{
$this->facebook = new Facebook(['appId' => 123, 'secret' => 'cohaaagan']);
}
}
class BarController
{
private $facebook;
public function __construct()
{
$this->facebook = new Facebook(['appId' => 123, 'secret' => 'cohaaagan']);
}
}
30. IoC Container
class AppServiceProvider extends ServiceProvider {
public function register() {
$this->app->bind('Facebook', function() {
return new Facebook(['appId' => 123, 'secret' => 'cohaaagan']);
});
}
}
โ You can โtellโ Laravel to provide a fully instantiated class
instead of the requested class
31. IoC Container
class FooController {
private $facebook;
public function __construct() {
$this->facebook = App::make('Facebook');
}
}
class FooController {
private $facebook;
public function __construct(Facebook $facebook) {
$this->facebook = $facebook;
}
}
34. Contracts
โ Also known as โInterfacesโ
โ De๏ฌne the โPublic APIโ of your classes
โ Packaged as part of L5
โ One for each of the the core Laravel services
โ Help you โdecoupleโ your code
35. Contracts
class UserController
{
public function __construct(SomeVendorMailGun $mail) {
$this->mail = $mail;
}
public function registerUser() {
$this->mail->send(...);
}
}
โ โTightly coupledโ
โ What would happen if we changed from MailGun
to Mandrill, or Gmail?
36. Contracts
namespace IlluminateContractsMail;
interface Mailer {
public function raw($text, $callback);
public function send($view, array $data, $callback);
public function failures();
}
class UserController
{
public function __construct(IlluminateContractsMailMailer $mail) {
$this->mail = $mail;
}
public function registerUser() {
$this->mail->send(...);
}
}
37. Contracts
use IlluminateContractsMailMailer;
class FacebookMailer implements Mailer
{
public function raw($text, $callback) {};
public function send($view, array $data, $callback) {};
public function failures() {};
}
class AppServiceProvider extends ServiceProvider {
public function register() {
$this->app->bind('IlluminateContractsMailMailer', function() {
return new FacebookMailer();
});
}
}
38. Contracts
class UserController
{
public function __construct(IlluminateContractsMailMailer $mail) {
$this->mail = $mail;
}
public function registerUser() {
$this->mail->send(...);
}
}
class AppServiceProvider extends ServiceProvider {
public function register() {
$this->app->bind('IlluminateContractsMailMailer', function() {
return new TwitterMailer();
});
}
}
40. File Drivers
โ Improved version of the previous Filesystem class
โ Now powered by Flysystem
(๏ฌysystem.thephpleague.com)
โ Allows for local & remote ๏ฌlesystems at the same
time
โ Compatible with S3 & Rackspace
โ Support available for lots of others
composer require league/flysystem-aws-s3-v2 ~1.0
composer require league/flysystem-rackspace ~1.0
44. Method Injection
โ Uses the IoC container to resolve dependencies
injected directly into a method.
โ Helps cut down on cluttered constructor methods
class UserController {
public function registerUser(Mailer $mail) {
// do some registration stuff
$mail->send();
}
// Route::post('user/{id}/mail', 'UserController@mailUser');
public function mailUser($userId, Mailer $mail) {
// do some registration stuff
$mail->send();
}
}
47. Form Requests
โ Aim to standardise and simplify form validation
โ Validation in V3/4 was verbose:
class UserController
{
public function register()
{
$rules = [
'name' => 'required',
'email' => 'email|required'
];
$validator = Validator::make(Input::all(), $rules);
if($validator->fails()) return redirect()->back()->withErrors();
// validation passed, do something...
}
}
48. Form Requests
โ Form requests make things very cleanโฆ
class UserController
{
public function register(RegisterUserRequest $request)
{
// validation passed, do something...
}
}
โ Automatically validates
โ Automatically redirects back, with errors
49. Form Requests
โ How to generate a request
php artisan make:request RegisterUserRequest
โ Stored in app/Http/Requests
class RegisterUserRequest extends Request {
public function authorize() {
return false;
}
public function rules() {
return [
'name' => 'required',
'email' => 'email|required'
];
}
}
50. Forms & HTML Helpers
โ Uses an expressive syntax to generate form ๏ฌelds
& HTML entities
โ Removed from L5 as default
โ Available as a composer package
composer require illuminate/html ~5.0
63. Command Bus
โ Separates the logic of you application into small,
manageable actions
โ Creates reusable classes that can be used from
different access points to your application
โ Helps keep your code DRY
โ Helps make your code testable
65. Command Bus
[ request ]
[ command ]
[ bus ]
[ handler ]
A data transfer object, or message, which
contains only the information required for
carrying out a speci๏ฌc action
Matches a command to the corresponding
handler and executes it
Responsible for carrying out the โtaskโ in
response to the command.
66.
67. Command Bus
[ request ]
[ command ]
[ bus ]
[ handler ]
POST
/user/register
RegisterUser
RegisterUserHandler
POST
/user/updatePassword
UpdateUserPassword
UpdateUserPasswordHandler
68. Creating a command
class RegisterUser extends Command
{
public $name;
public $email;
public $password;
public function __construct($name, $email, $password)
{
$this->name = $name;
$this->email = $email;
$this->password = $password;
}
}
php artisan make:command RegisterUser
app/Commands/RegisterUser.php
69. Dispatching the command
class UserController extends Controller {
use DispatchesCommands;
public function postRegister(RegisterUserRequest $request)
{
$this->dispatch(new RegisterUser(
$request->get('name'),
$request->get('email'),
$request->get('password')
));
// OR
$this->dispatchFrom(RegisterUser::class, $request);
}
}
70. The Command Handler
class RegisterUserHandler
{
public function handle(RegisterUser $command)
{
$user = User::create([
'name' => $command->name,
'email' => $command->email,
'password' => Hash::make('password')
]);
}
}
php artisan handler:command RegisterUserHandler
71. Creating a command
class UpdateUserPassword extends Command
{
public $userId;
public $password;
public function __construct($userId, $password)
{
$this->userId = $userId;
$this->password = $password;
}
}
php artisan make:command UpdateUserPassword
app/Commands/UpdateUserPassword.php
72. The Command Handler
class UpdateUserPasswordHandler
{
public function handle(RegisterUser $command)
{
$user = User::find($command->userId);
$user->updatePassword(
Hash::make($command->password)
);
}
}
php artisan handler:command UpdateUserPasswordHandler
73. Queued Commands
php artisan make:command ExampleQueuedCommand --queued
use IlluminateQueueSerializesModels;
use IlluminateQueueInteractsWithQueue;
use IlluminateContractsQueueShouldBeQueued;
class ExampleQueuedCommand extends Command implements ShouldBeQueued
{
use InteractsWithQueue, SerializesModels;
public function __construct()
{
//
}
}
75. Events
โ Also known as the Publish-Subscribe pattern
โ Used to model concerns of the application youโre
building
โ Work in a similar way to Commands
76. Generating An Event
php artisan make:event UserWasRegistered
use AppEventsEvent;
use IlluminateQueueSerializesModels;
class UserWasRegistered extends Event {
use SerializesModels;
public $user;
public function __construct(User $user)
{
$this->user = $user;
}
}
app/EventsUserWasRegistered.php
77. The Event Handler
class SendRegistrationConfirmation {
public function __construct()
{
//
}
public function handle(UserWasRegistered $event)
{
// send mail
}
}
php artisan handler:event SendRegistrationConfirmation --event=UserWasRegistered
79. Firing Events
class RegisterUserHandler
{
public function handle(RegisterUser $command)
{
// register the user $user
Event::fire(new UserWasRegistered($user));
}
}
app/Handlers/Commands/RegisterUserHandler.php
81. Optional Packages
โ Socialite
โ Provides a consistent interface for
authentication using social networks
โ Returns a consistent user object & API to get
name, email, avatar, etc
composer require "laravel/socialite": "~2.0"
82. Optional Packages
โ Cashier
โ Provides a ๏ฌuent interface for Stripe
โ Handles creating/modifying subscriptions,
recurring charges, free trials, failed payments
and invoices
composer require "laravel/cashier": "~3.0"