Laravel

Routing

Resources

Create index and store routes

Route::resource('chirps', ChirpController::class)
    ->only(['index', 'store', 'update', 'destroy'])
    ->middleware(['auth', 'verified']);

These create routes for the components: ex. 'chirps.destroy'

Update example

The dependency injection parses the chirp from the resource route /chirps/{chirp} and injects it

You don't have to call the method. Laravel's routing does that automatically when the parameters match

class ChirpController extends Controller
{
  public function update(Request $request, Chirp $chirp): RedirectResponse
    {
    }
}

Route::patch('/chirps/{chirp}', [ChirpController::class, 'update'])->name('chirp.update');

Middleware

  • Examples: Rate-Rate Limiting, logging, caching, CSRF, email-verified users
  • Define middleware groups in app/Http/Kernel.php

Wrap routes in a middleware group:

Route::middleware('guest')->group(function () {
  Route::get('register', [RegisteredUserController::class, 'create'])->name('register');

  Route::post('register', [RegisteredUserController::class, 'store']);
});

Controllers

Naming conventions

indexGETget the view at the route
createGETdisplay the form to create a new _
storePOSTsave new resources to the db
showGETshow something (but not a full page, that's index)

POST requests automatically include CSRF protection. So any route that modifies server state should be a POST request

Database Interactions

Use TablePlus for a database GUI

# php artisan tinker
App\Models\Chirp::all();

Relationships, Models

Establishing relationships lets you do things like:

$request->user()->chirps()->create($validated);

// app/Models/User.php
class User extends Authenticatable
{
    // Enable mass assignment for this attribute
    protected $fillable = [
        'message',
    ];

    public function chirps()
    {
        return $this->hasMany(Chirp::class);
    }
}

class Chirp extends Model
{
    // Access as a property, not a method. Ex. $chirp->user
    public function user()
    {
        return $this->belongsTo(User::class);
    }
}

Migrations

<?php

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('chirps', function (Blueprint $table) {
            $table->id();
            $table->foreignId('user_id')->constrained()->cascadeOnDelete();
            $table->string('message');
            $table->timestamps();
        });
    }
};

Factories

Used to seed your DB

php artisan tinker
> App\Models\Job::factory()->create();

# or
> App\Model\Job::factrory()->unverified()->create();

Eloquent

// lazy load - can cause the N+1 problem
$jobs = Jobs::all();
$jobs[0]->salary;

Job::create(['title' => 'Director', 'salary' => '$1,000,000']);

Job::find(7)->delete(); // find id 7 then delete it

Job::first();

// ex. if job belongsTo employer
// latest is essentially an ORDER BY
Job::with('employer')->latest()->simplePaginate(3);

Artisan

php artisan make:model -mrc Chirp

php artisan migrate:fresh # reset the database

Policies

  • No policy class => everything is allowed

  • Policy class => Nothing is allowed except what's specified in the policies

  • Lets you define rules for controller commands

    class PostPolicy
    {
        public function update(User $user, Post $post): bool
        {
            return $user->id === $post->user_id;
        }
    }
    
    // in the route
    Route::get('users/create', function() {
        Return Inertia::render('Users/Create', [
            'can' => Auth::user()->can('create', User::class);
        ]);
    })->middleware('can:create,App\Models\User');

Events

  • Add listeners to things that happen
php artisan make:listener SendChirpCreatedNotifications --event=ChirpCreated

ext: https://bootcamp.laravel.com/inertia/notifications-and-events

Registering Global Components

// in app.js
  setup({ el, App, props, plugin }) {
    createApp({ render: () => h(App, props) })
      .use(plugin)
      .commponent("Link", Link)
      .mount(el)
  },

Default Layouts

createInertiaApp({
  title: title => `${title} - ${appName}`,
  resolve: name =>
    let page = require(`.Pages/${name}`).default;
    page.layout ??= Layout;
  )
}

Frontend

<script setup>import { Head } from "@inertiajs/inertia-vue3"</script>
<template>
  <title>My App</title>
</template>

Useful Functions

$job = Arr::first($jobs, fn($job) => $job['id'] == $id)

Request Validation

$request->validate([
    'name' => ['required'],
    'email' => ['required', 'email', 'unique:users,email'],
    'password' => ['required', Password::min(6)],
])