24 March, 2018

Let's Build a Forum with Laravel and TDD is a mega-tutorial (102 lessons) by Jeffrey Way on his Laracasts site. It's a massive, time-intensive beast that contains lots of useful info, and not least gives the opportunity to watch someone build a fairly complex website from scratch. But its size means that a lot of little tricks and tips are hidden away inside the videos. While each lesson's title reflects a particular feature Jeffrey Way wants to build, I found that there are also particular technical nuggets of info to be found among the broader strategies. So this is a list of any little snippets that cropped up in the course, just minor points I didn't know or found useful. This post contains 50 tips, covering lessons 1-42. See Part 2 here!

When making a model in artisan, and -mr to make the migration ( m ), and a resourceful controller ( r ). Or use c for a plain controller. [Source]

For testing we can use an SQLite database in memory. In phpunit.xml set DB_CONNECTION to sqlite and DB_DATABASE to :memory: . [Source]

latest() is an Eloquent relation that is basically an alias for orderBy('created_at', 'desc') . [Source]

Put code common to all tests in a test file in a setUp method that calls parent::setUp(); . [Source]

Call diffForHumans() on Carbon instances (like created_at fields in Eloquent models) to output something like "2 days ago". [Source]

Add the --filter flag to phpunit to run only one test. [Source]

Instead of specifying mass-assignable fields in a model with fillable , you can set the $guarded variable to block specific fields, or set it to an empty array to make every field assignable. [Source]

back() is a helper function to return the user to the previous location. [Source]

Note the distinction between create and make model factory methods: create persists the model to the database, while make only stores it in memory. [Source]

The raw model factory method returns an array of the model data, rather than the Eloquent model. [Source]

Add only() to restrict middleware to particular methods in a controller. E.g. in the constructor:

$this - > middleware ( 'auth' ) - > only ( 'store' ) ;

[Source]

Or use except() for the opposite. [Source]

Use the exists validation rule to check whether a given field exists in a specified database table. [Source]

You can use whereSlug and whereId as aliases for where('slug', $slug) and where('id', $id) in Eloquent calls. [Source]

To change the key used in route-model binding, override the getRouteKeyName method in your model. E.g.

public function getRouteKeyName ( ) { return 'slug' ; }

[Source]

If you need some data to be passed to all your views, you don't need to use a view composer, you can use the much simpler share method. [Source]

JW says that he uses "query objects" - classes that correspond to a complex SQL query - in the Laracasts codebase. E.g. App/Queries/ThreadsQuery . [Source]

You can retrieve only a portion of the request data using $request->only(['foo', 'bar']) . It saves requesting everything then filtering through it. [Source]

Performing count() on a relationship given as a dynamic property (e.g. $thread->replies->count() ) requires a redundant SQL query that will fetch all the replies. If we substitute the method for the property (e.g. $thread->replies()->count() ) the SQL query only gets the count of the replies. As the docs say: "all types of Eloquent relationships also serve as query builders, allowing you to continue to chain constraints onto the relationship query before finally executing the SQL against your database". [Source]

The Eloquent load method permits "lazy eager loading", i.e. eager loading a relationship after the model has been retrieved. [Source]

The Eloquent withCount method is a way of counting the results of a relationship without loading them. [Source]

Eloquent global query scopes define constraints applicable to all queries on that model. [Source]

Laravel's str_plural helper returns the appropriate plural form of a string. [Source]

The toSql method returns the SQL query of a given Eloquent query. [Source]

The whole section on polymorphic relations was new to me. [Source]

In database migrations, create a unique combined index with unique ; e.g. $table->unique(['user_id', 'favorited_id', 'favorited_type']); . [Source]

JW: "One of the downsides" of Eloquent is its tendency to hide the presence of multiple SQL queries when accessing relationships between models. [Source]

Global eager loading in an Eloquent model is possible by overriding the $with property. E.g.

protected $with = [ 'owner' ]

[Source]

You can use model events to (among other things) delete related models when a model is deleted. E.g. in the boot method of a model:

static : : deleting ( function ( $thread ) { $thread - > replies ( ) - > delete ( ) ; } ) ;

[Source]

The method_field helper spoofs HTTP verbs in forms. E.g.

{ { method_field ( 'DELETE' ) } }

[Source]

Use @forelse and @empty to show messages when a collection of data to be looped through is empty. [Source]

The artisan make:policy command generates an empty policy class. The flag --model=Foo adds some boilerplate. [Source]

The @can and @cannot Blade directives check whether the logged in user can perform a given action. [Source]

To give a super admin permission to perform all actions, either use the before method on a policy, or to apply this to all policies use the Gate class in the boot method of AuthServiceProvider . E.g.:

Gate : : before ( function ( $user ) { if ( $user - > name === 'super admin' ) return true ; } ) ;

[Source]

Not Laravel specific, but to get the short name of a class (i.e. without the namespace), this can be done with the ReflectionClass method getShortName . E.g.:

$name = ( new \ ReflectionClass ( $thread ) ) - > getShortName ( ) ;

[Source]

You can move boot methods from specific models to traits they use with the function boot[TraitName] in the trait. E.g.:

protected static function bootRecordsActivity ( ) { }

[Source]

You can pass a closure to the groupBy method. [Source]

Chain the with method to a redirect response to flash data to the session. [Source]

Use the @includeIf Blade directive to only include a view if it exists. Inspired by (this video).

Use inline templates to use a Blade file (or other HTML) as a Vue component's template. [Source]

Use the v-cloak directive, in combination with a CSS rule like [v-cloak] { display: none; } , to hide a Vue component until it's loaded. [Source]

Use the appends property to add Eloquent attributes to a model's array or JSON representation. [Source]

Use the Eloquent fresh method to reload a model from the database. [Source]

For a model event (e.g. deleting ) to fire, the model has to be deleted (or updated etc.), rather than building an SQL command with the query builder. I.e. this:

$this - > favorites ( ) - > where ( $attributes ) - > get ( ) - > each ( function ( $favorite ) { $favourite - > delete ( ) ; } ) ;

instead of

$this - > favorites ( ) - > where ( $attributes ) - > delete ( ) ;

[Source]

Higher order messages are "properties" to make performing tasks on collections more readable. E.g., using the each higher order message:

$this - > favorites ( ) - > where ( $attributes ) - > each - > delete ( ) ;

[Source]

The Vue v-for directive can take a second argument that supplies the index of an item. E,g.:

< div v-for = " (reply, index) in items " <reply :data = " reply " @deleted = " remove(index) " > </ reply > </ div >

[Source]

Use Vue mixins for creating reusable functionality. [Source]

A Vue watcher can be used to perform some new function when a component's data changes. [Source]

In Vue, the .prevent event modifier will perform the equivalent of preventDefault() . E.g. @click.prevent . [Source]

increment and decrement are database query builder helpers to increment or decrement the value of a column. [Source]

To append an attribute to a single instance of an Eloquent model (rather than to every instance as in 41 above), use the append method. [Source]

Click here for Part 2, covering the second half of the series.