Laravel: Some Shifty Bits
Jason McCreary

Talk: PG-13

Created Basecode podcast, Laravel Shift

Today, sharing code samples from shift analytics

Casting

Not much attribute casting done (e.g. $casts = ['user_id' => 'integer', 'active' => 'boolean'];)

Can matter when the underlying data structure doesn't store it in that type (e.g. MySQL storing a boolean as tinyint) or when setting the thing directly on the model

Can also cast as an array!

Can also set up getXAttribute/setXAttribute methods on a model

Gotcha: Array union. Use a temporary

Model Relationships

// Direct mapping
$setting->user_id = $user->id;

// Indirect mapping
$setting->user()->associate($user);
$setting->user()->disassociate($user);

// Handy for many-to-many
$user->settings()->attach($setting);
$user->settings()->detach($setting);

Pivots

Intermediary tables for many-to-many associations

Example: Team can have many users, users can be on many teams

Say there's an approval process for a team.

public function teams()
{
   return $this->belongsToMany(Team::class)->wherePivot('approved', 1);
}

Can do pivot class!

class Membership extends Pivot {
  protected $table = 'team_user';
  public $incrementing = true;

  // Binds
  protected $with = ['user', 'team'];

  public function user() { return $this->belongsTo(User::class); }
  public function team() { return $this->belongsTo(Team::class); }
}

In RoR, when reaching for complex relationships, can also define it

MorphMap

Custom Polymorphic Types

Decoupling database from internal application structure

Can define it yourself

Relation::morphMap([
  'posts' => 'Model\Post',
  'videos' => 'Model\Video'
]);

Views

@if/@endif's is common, but there's also...

Also, Blade directives like @csrf (beats csrf_token() and csrf_method())

$loop also has index, iteraiton, remaining, count, first, last properties

Performance

When you have a View composer, you can share settings everywhere. Quick, easy, great...but runs for every single view, including partials, sidebars, headers...could run multiple times!

Instead, target high-level (e.g. layout), not wildcard

Responses

try {
  if ($connection->isGitLab()) {
    GitLabClient::addCollaborator($connection->access_token);
  }
} catch (GitLabClientException $e) {
  Log::error();
  return redirect()->back()->withInput($request->input());
}

Instead, extend a custom Exception, then override the render method and to do the catch stuff.

Form Requests

There are redirection properties like $redirect, $redirectRoute, $redirectAccess for URIs/routers/controller actions to redirect to when an action fails

API Responses

Can extend JsonResource and implement toArray, withResponse...

Authentication

Laravel provides tons of different hooks. Instead of replacing/rewriting, you can just replace authenticated for additional login acctions and change response

Authorization

Might have $this->ensureUserCanViewVideo($user, $video) call that either returns or abort(403)'s.

Instead, use gates/policies. Policies map better to models

Gate::define('watch-video', function ($user, $lesson) {
   return $lesson->isFree();
})

abort_unless(Gate::allows('watch-video', ...))

Also has blade directives! @can

Signed URLs and Temporary Signed URLs

Prevent someone from changing user_id, team_id, etc. ($this->middleware('signed'))

Response chains

If you're not authorized, respond with response(null, 403); Instead, do a chain (return response()->noContent(403);) or just abort(403)

Or abort_if, abort_unless, throw_if, throw_unless

@gonedark on Twitter

https://bit.ly/subscribe-jmac