Upgrade to Pro — share decks privately, control downloads, hide ads and more …

I Didn't Know Laravel Could Do That!

I Didn't Know Laravel Could Do That!

If you’re into to Laravel, you’ve probably already tried out the basic MVC features. What you probably haven’t gotten to yet is all of the amazing features that make Laravel truly a “full stack” framework. In this talk, we’ll cover queueing jobs, send emails, search, browser tests, event broadcasting and more. This will be a great crash course on letting Laravel do the heavy lifting for you, and making sure you know what it’s capable of so you don’t accidentally reinvent the wheel.

44a352b02a91a9e841da7533bc5d9b8e?s=128

Josh Butts

April 20, 2018
Tweet

Transcript

  1. I Didn’t Know Laravel Could Do That! Josh Butts Longhorn

    PHP 2018
  2. About Me • SVP of Engineering,
 Ziff Davis • Austin

    PHP Organizer • github.com/jimbojsb • @jimbojsb 2
  3. Preface • I really used to dislike Laravel • I

    used to thing everyone had a smug sense of superiority • I used to think the only way to write PHP was explicitly • I’ll admit it, I was wrong 3
  4. Agenda • Job & Queues • Email • Scout •

    Dusk • Echo 4
  5. Jobs & Queues

  6. Laravel Queues - Why? • Offload slow tasks to asynchronous

    back- end processes • Keep web response time snappy • Especially for integrations with remote services • Things that have complex failure models 6
  7. Laravel Queues • Built in to the framework • Various

    drivers for the queue service of your choice • Many other first-class parts of the framework are natively queue-able 7
  8. Configuring Queues • Set the queue driver of your choice

    in your .env file (you don’t want sync) • Use artisan to make a failed jobs table (optional) • If using DB driver, use artisan to make a jobs table • Set up credentials for whatever queue service you need in config/queue.php or .env 8
  9. DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=homestead DB_USERNAME=homestead DB_PASSWORD=secret BROADCAST_DRIVER=log CACHE_DRIVER=file SESSION_DRIVER=file SESSION_LIFETIME=120

    QUEUE_DRIVER=sync REDIS_HOST=127.0.0.1 REDIS_PASSWORD=null REDIS_PORT=6379
  10. An Aside…

  11. For the love of God, please don’t use your database

    as a job queue
  12. Anatomy of a Job

  13. php artisan make:job MessageLoggerJob

  14. <?php namespace App\Jobs; use Illuminate\Bus\Queueable; use Illuminate\Queue\SerializesModels; use Illuminate\Queue\InteractsWithQueue; use

    Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; class MessageLoggerJob implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; /** * Create a new job instance. * * @return void */ public function __construct($message) { } /** * Execute the job. * * @return void */ public function handle() { } }
  15. use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; class MessageLoggerJob implements ShouldQueue

    { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; private $message; public $tries = 5; public $timeout = 600; public $delay = 5; /** * Create a new job instance. * * @return void */ public function __construct($message) { $this->message = $message; } /** * Execute the job. * * @return void */ public function handle() { logger()->info($this->message); } }
  16. Dispatching Jobs

  17. <?php namespace App\Http\Controllers; use App\Jobs\MessageLoggerJob; use Illuminate\Http\Request; class JobDispatcherController extends

    Controller { public function index(Request $request) { $job = new MessageLoggerJob($request->get('message')); dispatch($job); } }
  18. Processing Jobs

  19. php artisan queue:work

  20. php artisan queue:work --once

  21. Laravel Horizon • Fancy dashboard to manage all your queues

    • Has baked in assumptions about your deployment infrastructure • Manages supervisors for queue workers 21
  22. Laravel Horizon 22

  23. Email

  24. Sending Emails • Uses SwiftMailer under the hood • Create

    objects to represent emails • Email objects are natively queue-able • Email bodies are rendered using blade • Emails are natively aware of Laravel users for name and email address 24
  25. Anatomy of an Email

  26. php artisan make:mail WelcomeEmail

  27. use Illuminate\Mail\Mailable; use Illuminate\Queue\SerializesModels; use Illuminate\Contracts\Queue\ShouldQueue; class WelcomeEmail extends Mailable

    { use Queueable, SerializesModels; public function __construct() { // } public function build() { return $this->view('view.name'); } }
  28. class WelcomeEmail extends Mailable { use Queueable, SerializesModels; private $user;

    public function __construct(User $user) { $this->user = $user; } public function build() { return $this->view('welcome.blade.php'); } }
  29. class WelcomeEmail extends Mailable implements ShouldQueue { use Queueable, SerializesModels;

    private $user; public function __construct(User $user) { $this->user = $user; } public function build() { $this->subject("Welcome to Our App"); $this->from("welcome@app.com"); return $this->view('welcome.blade.php'); } }
  30. <html> <body> <h1>Welcome to our app, {{$user->name}}</h1> <p>Please confirm your

    email, <a href="{{url(route("email_confirm"))}}">click here</a> </p> </body> </html>
  31. Sending Emails

  32. <?php namespace App\Http\Controllers; use App\Mail\WelcomeEmail; use App\User; use Illuminate\Http\Request; use

    Illuminate\Support\Facades\Mail; class MailSenderController extends Controller { public function index(User $user) { $mail = new WelcomeEmail($user); Mail::to($user)->send($mail); } }
  33. <?php namespace App\Http\Controllers; use App\Mail\WelcomeEmail; use App\User; use Illuminate\Http\Request; use

    Illuminate\Support\Facades\Mail; class MailSenderController extends Controller { public function index(User $user) { $mail = new WelcomeEmail($user); Mail::to($user)->queue($mail); } }
  34. Search

  35. Nobody ever wants to build search • Good news, its

    basically free in Laravel • Well, free as free time, but not necessarily free as in beer • Works best with Algolia, which is totally worth whatever you pay them 35
  36. Install Laravel Scout

  37. composer require laravel/scout php artisan vendor:publish

  38. A word on Algolia

  39. 'algolia' => [ 'id' => env('ALGOLIA_APP_ID', ''), 'secret' => env('ALGOLIA_SECRET',

    ''), ],
  40. Make your models searchable

  41. <?php namespace App; use Illuminate\Database\Eloquent\Model; use Laravel\Scout\Searchable; class BlogPost extends

    Model { use Searchable; }
  42. Index all the things

  43. php artisan scout:import "App\BlogPost"

  44. BlogPost::all()->searchable();

  45. Search for things

  46. BlogPost::search("release notes")->get();

  47. Drawbacks • Scout is EASY • There are tradeoffs •

    Scout hides the true power of Algolia and other engines 47
  48. Browser Tests

  49. Wait I already knew this one • Laravel comes with

    really nice HTTP dispatching tests built in • These won’t be sufficient for SPAs or apps that have Vue or React components 49
  50. Laravel Dusk

  51. composer require --dev laravel/dusk

  52. Writing Dusk Tests

  53. php artisan dusk:make MyHomepageTest

  54. <?php namespace Tests\Browser; use Tests\DuskTestCase; use Laravel\Dusk\Browser; use Illuminate\Foundation\Testing\DatabaseMigrations; class

    MyHomepageTest extends DuskTestCase { public function testExample() { $this->browse(function (Browser $browser) { $browser->visit('/') ->assertSee('Laravel'); }); } }
  55. use Laravel\Dusk\Browser; use Illuminate\Foundation\Testing\DatabaseMigrations; class MyHomepageTest extends DuskTestCase { /**

    * A Dusk test example. * * @return void */ public function testExample() { $this->browse(function (Browser $browser) { $browser->visit('/') ->drag('#available', '#selected') ->assertSee('Success!'); }); } }
  56. Running Dusk Tests

  57. php artisan dusk

  58. OMG SCREENSHOTS

  59. None
  60. Events

  61. Events • Laravel ships with a full-featured event bus •

    Create event objects • Dispatch events • Listen for events • Queue events • Broadcast events 61
  62. Creating Events

  63. php artisan make:event SignupEvent

  64. use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; class SignupEvent { use

    Dispatchable, InteractsWithSockets, SerializesModels; public function __construct() { // } public function broadcastOn() { return new PrivateChannel('channel-name'); } }
  65. use Illuminate\Broadcasting\InteractsWithSockets; use Illuminate\Contracts\Broadcasting\ShouldBroadcast; class SignupEvent { use Dispatchable, InteractsWithSockets,

    SerializesModels; public $user; public $request; public function __construct(User $user, Request $request) { $this->user = $user; $this->request = $request; } }
  66. Dispatching Events

  67. <?php namespace App\Http\Controllers; use App\Events\SignupEvent; use App\User; use Illuminate\Http\Request; class

    SignupController extends Controller { public function register(Request $request) { $user = new User($request->all()); $user->save(); $event = new SignupEvent($user, $request); event($event); } }
  68. Listening for Events

  69. php artisan make:listener SignupListener

  70. <?php namespace App\Listeners; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; class SignupListener {

    public function __construct() { // } public function handle($event) { // } }
  71. <?php namespace App\Listeners; use App\Mail\WelcomeEmail; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Contracts\Queue\ShouldQueue; use

    Illuminate\Support\Facades\Mail; class SignupListener { public function handle($event) { $mail = new WelcomeEmail($event->user); Mail::to($event->user)->send($mail); } }
  72. Broadcasting Events • Laravel can sent your events real-time to

    the client using Web Sockets • Laravel Echo JS lib • Laravel doesn’t natively have a socket server, and PHP is terrible for this • Native Pusher, Socket.io support 72
  73. Broadcasting Events

  74. class FollowedEvent implements ShouldBroadcast { use Dispatchable, InteractsWithSockets, SerializesModels; public

    $user; public $followedBy; public function __construct(User $user, User $followedBy) { $this->user = $user; $this->followedBy = $followedBy; } public function broadcastOn() { return new PrivateChannel($this->user->id); } }
  75. Dispatching Broadcasts

  76. Dispatching Broadcasts… is exactly like dispatching other events.

  77. Receiving Events in the Browser

  78. npm install --save laravel-echo

  79. Find a Web Socket Server

  80. window.Echo = new Echo({ broadcaster: 'pusher', key: ‘…’, cluster: 'us',

    encrypted: true }); Echo.private(user.id) .listen('Followed', function(e) { // maybe append a flash-messagy-sorta-thing? });
  81. Questions? https://joind.in/talk/427b0

  82. We’re Hiring - NYC, Montreal 82