Anzeige
Anzeige

Más contenido relacionado

Anzeige

Último(20)

What's New In Laravel 5

  1. LARAVEL 5 Darren Craig @minusdarren
  2. @minusdarren Introduction Darren Craig CTO - @minus40co ★ Built my first 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
  4. Overview
  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
  8. Included Tools
  9. PHPSpec ★ Testing library ★ Uses “Design by Specification” 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; } }
  11. Elixir ★ Wrapper for GulpJS var elixir = require('laravel-elixir'); elixir(function(mix) { mix.less('app.less'); mix.styles([ "normalize.css", "main.css" ], 'public/build/css/everything.css'); mix.version(["css/all.css", "js/app.js"]); }); href=“/css/all-16d570a7.css“><link rel="stylesheet" href="{{ elixir("css/all.css") }}">
  12. Directory Structure
  13. Directory Structure ★ Config, DB, Views moved above the app directory ★ New directories within app/ ★ No “models” directory ★ Leverages PSR-4 autoloading
 (http://www.php- fig.org/psr/psr-4/) ★ App/ namespace = app/ folder php artisan app:name Acme
  14. Directory Structure app Commands Console Events Handlers Commands Events Http Controllers Middleware Requests Providers Services bootstrap config database migrations seeds public package resources lang views storage cache logs meta sessions views work tests
  15. Service Providers ★ Bootstrap/configure classes in your application ★ app/Providers ★ AppServiceProvider.php ★ BusServiceProvider.php ★ ConfigServiceProvider.php ★ EventServiceProvider.php ★ RouteServiceProvider.php ★ Referenced in config/app.php
  16. Routes ’n Things
  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 file ★ Drastically speeds up applications with lots of routes php artisan route:cache
  22. Eloquent
  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
  26. IoC Container
  27. 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(); } }
  28. 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']); } }
  29. 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
  30. 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; } }
  31. Contracts
  32. Contracts ★ Also known as “Interfaces” ★ Define 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
  33. 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?
  34. 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(...); } }
  35. 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(); }); } }
  36. 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(); }); } }
  37. File Drivers
  38. File Drivers ★ Improved version of the previous Filesystem class ★ Now powered by Flysystem (flysystem.thephpleague.com) ★ Allows for local & remote filesystems 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
  39. File Drivers - Configuration // config/filesystems.php return [ 'default' => 'local', 'cloud' => 's3', 'disks' => [ 'local' => [ 'driver' => 'local', 'root' => storage_path().'/app', ], 's3' => [ 'driver' => 's3', 'key' => 'your-key', 'secret' => 'your-secret', 'region' => 'your-region', 'bucket' => 'your-bucket', ], 'rackspace' => [ 'driver' => 'rackspace', 'username' => 'your-username', 'key' => 'your-key', 'container' => 'your-container', 'endpoint' => 'https://identity.api.rackspacecloud.com/v2.0/', 'region' => 'IAD', ], ], ];
  40. File Drivers - Usage $disk = Storage::disk('cloud'); $disk = Storage::disk('local'); $disk = Storage::disk('s3'); $exists = Storage::disk('s3')->exists('file.jpg'); $exists = $disk->exists('file.jpg'); $file = Storage::get('file.jpg'); Storage::put('file.jpg', $contents); Storage::prepend('file.log', 'Prepended Text'); Storage::append('file.log', 'Appended Text'); Storage::delete('file.jpg'); Storage::delete(['file1.jpg', 'file2.jpg']); Storage::copy('old/file1.jpg', 'new/file1.jpg');
  41. Method Injection
  42. 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(); } }
  43. Form Requests
  44. 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... } }
  45. 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
  46. 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' ]; } }
  47. Forms & HTML Helpers ★ Uses an expressive syntax to generate form fields & HTML entities ★ Removed from L5 as default ★ Available as a composer package composer require illuminate/html ~5.0
  48. Middleware
  49. Middleware ★ Route Decorators ★ Similar to filters (still available) ★ Executed before the logic of your application
  50. Middleware ★ Stored in app/Http/Middleware: ★ Authenticate ★ RedirectIfAuthenticated ★ VerifyCSRFToken ★ Easy to add your own php artisan make:middleware WhitelistedIP
  51. Middleware class WhitelistedIP { $ipWhitelist = [ '123.123.123.123' ]; public function handle($request, Closure $next) { if(!in_array($request->getClientIp(), $this->ipWhitelist)) { return redirect('/'); } return $next($request); } }
  52. “After” Middleware class DoSomethingAfter { public function handle($request, Closure $next) { $response = $next($request); // Perform action return $response; } }
  53. Middleware <?php namespace AppHttp; use IlluminateFoundationHttpKernel as HttpKernel; class Kernel extends HttpKernel { protected $middleware = [ 'IlluminateFoundationHttpMiddlewareCheckForMaintenanceMode', 'IlluminateCookieMiddlewareEncryptCookies', 'IlluminateCookieMiddlewareAddQueuedCookiesToResponse', 'IlluminateSessionMiddlewareStartSession', 'IlluminateViewMiddlewareShareErrorsFromSession', 'AppHttpMiddlewareVerifyCsrfToken', 'AppHttpMiddlewareWhitelistedIP' ]; protected $routeMiddleware = [ 'auth' => 'AppHttpMiddlewareAuthenticate', 'auth.basic' => 'IlluminateAuthMiddlewareAuthenticateWithBasicAuth', 'guest' => 'AppHttpMiddlewareRedirectIfAuthenticated', 'whitelisted' => 'AppHttpMiddlewareWhitelistedIP', ]; }
  54. Applying Route Middleware Route::group('admin/*', ['middleware' => 'whitelisted', function() { // protected }]); class UserController extends Controller { public function __construct() { $this->middleware('auth'); $this->middleware('log', ['only' => ['fooAction', 'barAction']]); $this->middleware('subscribed', ['except' => ['fooAction', 'barAction']]); } }
  55. Cron & Scheduling
  56. Cron & Scheduling 15 6 2 1 * /home/melissa/backup.sh 17 6 2 1 * /home/carl/hourly-archive.sh 19 6 2 1 * /sites/my-site/artisan command:run 30 6 2 1 * /sites/my-site/artisan arnie:gettothechopper
  57. Laravel’s Scheduler // app/Console/Kernel.php class Kernel extends ConsoleKernel { protected function schedule(Schedule $schedule) { $schedule->command('inspire')->hourly(); $schedule->command('foo')->everyFiveMinutes(); $schedule->command('foo')->everyThirtyMinutes(); $schedule->exec('composer self-update')->daily(); $schedule->command('foo')->weekdays(); $schedule->command('foo')->mondays(); $schedule->command(‘foo')->sendOutputTo($filePath) ->emailOutputTo('foo@example.com'); } } * * * * * php /path/to/artisan schedule:run 1>> /dev/null 2>&1
  58. Command Bus
  59. 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
  60. Command Bus [ request ] [ command ] [ bus ] [ handler ]
  61. Command Bus [ request ] [ command ] [ bus ] [ handler ] A data transfer object, or message, which contains only the information required for carrying out a specific action Matches a command to the corresponding handler and executes it Responsible for carrying out the ‘task’ in response to the command.
  62. Command Bus [ request ] [ command ] [ bus ] [ handler ] POST /user/register RegisterUser RegisterUserHandler POST /user/updatePassword UpdateUserPassword UpdateUserPasswordHandler
  63. 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
  64. 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); } }
  65. 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
  66. 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
  67. 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
  68. 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() { // } }
  69. Events
  70. 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
  71. 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
  72. The Event Handler class SendRegistrationConfirmation { public function __construct() { // } public function handle(UserWasRegistered $event) { // send mail } } php artisan handler:event SendRegistrationConfirmation --event=UserWasRegistered
  73. Registering Events class EventServiceProvider extends ServiceProvider { protected $listen = [ UserWasRegistered::class => [ SendRegistrationConfirmation::class, GenerateHolidayEntitlement::class, SetServerPermissions::class, NotifyCurrentEmployees::class ] ]; } app/Providers/EventServiceProvider.php
  74. Firing Events class RegisterUserHandler { public function handle(RegisterUser $command) { // register the user $user Event::fire(new UserWasRegistered($user)); } } app/Handlers/Commands/RegisterUserHandler.php
  75. Optional Packages
  76. 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"
  77. Optional Packages ★ Cashier ★ Provides a fluent interface for Stripe ★ Handles creating/modifying subscriptions, recurring charges, free trials, failed payments and invoices composer require "laravel/cashier": "~3.0"
  78. Learning More
  79. Learning Laravel ★ Laravel Docs (http://laravel.com/docs) ★ Laracasts (http://laracasts.com) ★ Twitter @laravelphp ★ IRC ★ #Laravel ★ #Dev-Discussions
  80. Phew! Questions?
  81. Thanks! Pints? @minusdarren
Anzeige