Lessons from Laracasts, Part 2

This is part 2 of my collection of tips I've taken from Let's Build a Forum with Laravel and TDD, the mega-tutorial (102 lessons) by Jeffrey Way on his Laracasts site. Part 1 is here. This post contains 51 tips, covering lessons 43-102.


The artisan notifications:table command creates a migration for a table to hold database notifications. [Source]


The tap helper, inspired by Ruby can help refactoring by removing temporary variables. [Source]


Use the artisan event:generate command to create events and listeners. [Source]


The Notification::fake and Notification:assertSentTo methods allow you to test notifications without triggering their usual behaviour. [Source]


JW uses [identifier]CacheKey as a method to supply a single point of truth for a cache's key. [Source]


An example of using Laravel's container when refactoring spam inspection methods to their own classes: [Source], around 06:35.


The resolve method resolves a class out of Laravel's container. [Source]


JW uses a 422 Unprocessable Entity HTTP status code when catching exceptions thrown during AJAX calls. [Source]


Artisan's make:rule command will scaffold the necessary code for custom validation rules. [Source]


The throttle middleware rate limits access to Laravel routes. But JW notes that failing validation would make this solution problematic. [Source]


Use form requests for more complex form situations requiring authorization and validation. [Source]


The collect helper converts arrays to collections. [Source]


When the filter method is called without an argument on a collection it removes falsey values. [Source]


In the tutorial, JW uses the At.js library to add mentions autocomplete functionality to the forum. [Source]


Use the pluck method to get the values for a given key from a collection. JW uses it to return values from a collection retrieved by Eloquent:

return User::where('name', 'LIKE', '$search%')->take(5)->pluck('name');



One way to grab CSS from an NPM package: use the copy method in your webpack.mix.js file:

mix.js('resources/assets/js/app.js', 'public.js')
   .sass('resources/assets/sass/app.scss', 'public.css')
   .copy('node_modules/[path_to_src_css_file]', '[path_to_dest_css_file]');



Another way to grab a package's CSS: import it in your main scss file. [Source]


Another way to grab a package's CSS: just manually copy it to your css directory. [Source]


To import CSS files depending on the view, use a @yield('head') directive, then in the template you want to load this file, include the link tag in a @section('head') directive. [Source]


The UploadedFile::fake method allows you to fake a file (or image) for testing:

UploadedFile::fake()->image('filename.jpg', $width, $height)



The Storage::fake method will create a fake storage disk for testing. E.g.:


$this->json('POST', 'api/upload', [
  'file' => UploadedFile::fake()->image('filename.jpg')




hashName returns the filename for an uploaded file. [Source]


Compare Eloquent models with is and isNot. [From the comments to Source]


How did I not know about this? The input tag has an accept attribute which takes a comma-separated list of content type specifiers, either file extensions, MIME types or audio/*, video/* or image/*. [Source]


Any native attribute (e.g. name on a form element) specified on a Vue component instance will be passed to that component, when the root element of the component is a single form element. [Source]


As of PHP 7, you can use the null coalescing operator to assign a default value. E.g.:

return Redis::get($this->cacheKey()) ?? 0;


The steps to create a custom middleware:

  1. php artisan make:middleware NameOfMiddleware
  2. In the handle method of the new middleware write the code to filter access to the route:
if (! $request->user()->confirmed) {
  return redirect('/threads');
  1. List the middleware class in app/Http/Kernel.php:
protected $routeMiddleware = [
  'name-of-middleware' => NameOfMiddleware::class
  1. Attach the middleware to a route:
Route::post('threads', 'ThreadsController@store')->middleware('name-of-middleware');



To simulate a new user registration in a test you can call the event that's called by the register method in the RegistersUsers trait:

event(new Registered($user));



Faking emails while testing can be done with the Mail::fake method.


[test code here]




Eloquent models have a $cast property that, in the words of the docs, "provides a convenient method of converting attributes to common data types". Useful, for example, for converting 0 or 1 to booleans. [Source]


The forceCreate Eloquent method is like create except that it ignores any mass-assignment rules. [Source]


You can define modifications of your model factories with the state method. [Source]


Laravel's str-slug helper converts strings to slugs. [Source]


Use the query builder's max method to return the highest value of a given model field. E.g.:

$max = Book::wherePublisher('foobar')->max('pages');



As of PHP 7, you can access characters in strings using an offset in array-type brackets. To access the final character of string, use -1:

$final = $slug[-1];



Use the abort_if helper to throw an exception under a given boolean condition. [Source]


You can render an array as JSON in a blade template with the @json directive. [Source]


MySQL has a SET NULL action that can be set for UPDATE and DELETE operations on a foreign key. In a Laravel migration, this reads as:

  ->onDelete('set null');



If you get a "Cannot add foreign key constraint" error when migrating, that can be because the migration where you're setting the foreign key has a timestamp earlier than the migration for the table you're referencing in your foreign key. JW fixes this by manually altering the timestamp of the migration to a later date. [Source]


A potential error when using foreign keys and testing with an SQLite database: foreign keys are not enabled by default. To enable them, in your test include:

DB::statement('PRAGMA foreign_keys = ON');


NB. A comment to this video notes that instead you can use:



Use double negation (!!) to cast variables to a boolean. [Source]


Use the @php directive to embed PHP code in Blade views. [Source]


It is recommended not to reference the .env file within the application. Instead, pull environment variables from a configuration file (e.g. config/services.php) which itself pulls from .env. [Source]


Instead of getting the remote IP address with $_SERVER['REMOTE_ADDR'], use request()->ip(). [Source]


Use app()->runningUnitTests() for behaviour conditional on whether you're running your tests. [Source]


As of Laravel 5.5, validation returns the validated data, which makes it possible to create concise flows like this:

  'title' => 'required',
  'body' => 'required'



Using an external search service like Algolia can slow down tests. To circumvent this, set SCOUT_DRIVER to null in your test environment variables (phpunit.xml). For tests where you want to use the search service, you can update the config for that specific test:

config(['scout.driver' => 'algolia']);



For tests which use a search service, remember to remove any created elements at the end of the test to avoid false positives, with the unsearchable method on a collection. [Source]


Specify the data sent to your search service by overriding toSearchableArray in your model. [Source]


Any property passed to a Vue component that isn't accepted as a property in that component, will be assigned to the top-level element in that component's template. [Source]


When you want to display sanitized data in a Vue (or other front-end framework) component, and you want to sanitize it with PHP, you can do it with a custom accessor. [Source]