Laravel notes

3 May 2024

These are my notes for Laravel, where I save clever small scripts and various other information about Laravel. I'll update them continuously. The official Laravel documentation can be seen here: Laravel Documentation.

Table of contents

Installing a fresh Laravel project

composer create-project laravel/laravel example-app

Migration

You can tear down your database tables, recreate them and seed them again with the following command:
php artisan migrate:fresh --seed
Useful when running a local MySQL server in Docker during development.

Authentication

Install breeze scaffolding.
composer require laravel/breeze
php artisan breeze:install
php artisan migrate
npm install
npm run dev

Blade

Blade is Laravel's templating engine. This where you define your views. Split everything you can into different views and components — even down to e.g. an input field.

@foreach ($post->comments as $comment)
     
@endforeach
In your post/comment.blade.php file you need to define the variable.
@props(['comment'])
The variable can even have a default value.

Layout

I'll usually create a file resources/view/layout/app.blade.php that contains the basic template of the website. The basic template is split into html header, navigation, the actual content, and a footer.

Caching in Laravel

You can easily cache expensive operations in your Laravel application with the following:
cache()->remember('UNIQUE_CACHE_NAME', NUM_SECONDS, fn() => MY_FUNCTION());
Or if you are running multiple commands:
cache()->remember('UNIQUE_CACHE_NAME', NUM_SECONDS, function () {
    // My demanding code.
});
Simply replace UNIQUE_CACHE_NAME with something unique, e.g. a slug or whatever. Instead of writing the exact number of seconds to cache the operation at NUM_SECONDS, you can use Carbon\Carbon's now(), e.g. now()->addDays(7).

Database

Migrations

Foreign keys

Include a column for the foreign key and a reference column.
$table->foreignId('user_id');
$table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');

Indexes

Create indexes with the this commands:
$table->primary(['post_id', 'tag_id']);

Data types

Enums in Laravel

Since Laravel 9 there is enum attribute casting, meaning a string variable can be cast into an enum. This means you can avoid defining the enum in the database, which will only lead to trouble when working in teams.

You can define your enum like below. It is important to define each case as well as the return type.
namespace App/Enums;

enum State: string 
{
    case Draft = 'draft';
    case Published = 'published';
    case Archived = 'archived';
}
Then in your model, the relationship between the enum and the attribute on your model.
class Post extends Model
{
    protected $casts = [
        'state' => State::class,
    ];
}
With this in place, the string from the database in automatically cast into an enum.

The enum can also be used in custom validation like this:
use App\Enums\State;
use Illuminate\Http\Request;
use Illuminate\Validation\Rules\Enum;

$validated = $request->validate([
	'state' => ['required', new Enum(State::class)]
], [
	'state.Illuminate\Validation\Rules\Enum' => 'Wrong value',
]);

External libraries

For a certain project I needed to include a PHP library from a 3rd party into my Laravel application. I found the following post quite useful: How to use external classes and PHP files in Laravel Controller?

Packages

There tons of different very useful packages available for your Laravel project. I have written a small post about the packages that I use here:

Useful packages in Laravel

Routing

There are two primary ways I define my routes/web.php.
Route::get('my-uri', [MyController::class, 'my-function'])->name('my-named-route');

Route::controller(MyController::class)->group(function() {
    Route::get('my-uri', 'my-function')->name('my-named-route');
    // More routes to MyController.
});
With a named route, you can use
// Redirecting in a controller.
return redirect()->route('my-named-route');

// Using a named route in Blade.
{{ route('my-named-route') }}
You can also test the current URL. Here are 3 examples:
request()->is('contact-us') // returns true or false
request()->is('blog/' . $post->slug)
request()->is('blog/*')

Middleware

Here is a simple guide: Laravel 8 Middleware Example.

With middleware, you can “guard” routes like this:
Route::middleware('my-middleware')->group(function() {
    // My guarded routes.
});

Validation

Check out the built-in validation rules. It's the most visited page of the Laravel documentation. No wonder.

Handling validation errors

I always fiddle a bit with it in the beginning, so I insert this into the form to grab all errors.
@foreach ($errors->all() as $error)
    {{ $error }}
@endforeach
Usually I'll then graduate to something like this for each input field.
@error('username')
    
        {{ $message }}
    
@enderror
I'll also add the “is-invalid”-class to the input field.
@error('username') is-invalid @enderror
When handling a validation error, the page resets and all fields are emptied. Unless you use the old-function:
value={{ old('username') }}
The old-function works similar to coalesce, meaning you can add more values to it. This is very useful when e.g. editing a post. The value of the input field can be set like this:
value={{ old('text', $post->text) }}

Traits

Traits are used for reusing code. Check this answer on Laracasts, where a trait is used for defining validation rules for an address, which is then reused.

Here the trait is defined:
namespace App\Http\Requests;

trait CommonRules
{

    protected function addressRules()
    {
        return [
            'company_id'            => 'required|numeric',
            'address_line_1'        => 'required|min:3|max:80',
            'address_line_2'        => 'min:3|max:80',
            'address_line_3'        => 'min:3|max:80',
            'area_town'             => 'required|alpha|min:3',
            'county'                => 'required|min:3|max:80',
            'postcode'              => 'required',
            
        ];
    }
}
The trait can then be used in a request like this:
class CompanyFormRequest extends Request {

    use CommonRules;

    public function rules()
    {
        return array_merge($this->addressRules(), [
                'company'         => 'required',
                'entity_id'       => 'required|in:1,2,3,4,5,6',
                'email'           => 'required|email',
                'tel'             => 'required',
                'website'         => 'url',
            ]);
    }
}

Views

Handling empty models:
@if ($users->isEmpty())

You might also enjoy

Using Linode/Akamai for your S3 storage in Laravel

Using Linode/Akamai for your S3 storage in Laravel

Published 2024-05-05

Laravel

Web development

Implementing a S3 bucket from Linode/Akamai in your Laravel application

Read the post →
The Seven Restful Controller Actions in Laravel

The Seven Restful Controller Actions in Laravel

Published 2024-05-05 — Updated 2024-05-16

Laravel

PHP

Web development

The seven RESTful actions and how you could implement them in Laravel

Read the post →
Useful Laravel packages

Useful Laravel packages

Published 2024-05-05

Laravel

PHP

Web development

Learn what packages that can help you build even better websites in Laravel. We'll go trhough the must-haves and packages that are just nice to have.

Read the post →