27 April, 2018

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' ) ;

[Source]

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]' ) ;

[Source]

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 )

[Source]

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

Storage : : fake ( 'public' ) ; $this - > json ( 'POST' , 'api/upload' , [ 'file' = > UploadedFile : : fake ( ) - > image ( 'filename.jpg' ) ] ) ; Storage : : disk ( 'public' ) - > assertExists ( 'filename.jpg' ) ;

[Source]

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 ;

[Source]

The steps to create a custom middleware:

php artisan make:middleware NameOfMiddleware In the handle method of the new middleware write the code to filter access to the route:

if ( ! $request - > user ( ) - > confirmed ) { return redirect ( '/threads' ) ; }

List the middleware class in app/Http/Kernel.php :

protected $routeMiddleware = [ 'name-of-middleware' = > NameOfMiddleware : : class ] ;

Attach the middleware to a route:

Route : : post ( 'threads' , 'ThreadsController@store' ) - > middleware ( 'name-of-middleware' ) ;

[Source]

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 ) ) ;

[Source]

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

Mail : : fake ( ) ; [ test code here ] Mail : : assertSent ( MailableName : : class ) ;

[Source]

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' ) ;

[Source]

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 ] ;

[Source]

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:

$table - > foreign ( 'user_id' ) - > references ( 'id' ) - > on ( 'users' ) - > onDelete ( 'set null' ) ;

[Source]

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' ) ;

[Source]

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

Schema : : enableForeignKeyConstraints ( ) ;

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:

$thread - > update ( request ( ) - > validate ( [ 'title' = > 'required' , 'body' = > 'required' ] ) ) ;

[Source]

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' ] ) ;

[Source]

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]