Laravel Tips and Cheat Sheet Collection

Published: 2 years ago - Updated: 2 years ago

11 minutes - 766 Words

article 'Laravel Tips and Cheat Sheet Collection' banner

Summary

A collection of Laravel tips and useful information for Laravel developers.

Laravel CRUD Routes

Verb URI Action Route Name
GET /photos index photos.index
GET /photos/create create photos.create
POST /photos store photos.store
GET /photos/ show photos.show
GET /photos/{photo}/edit edit photos.edit
PUT/PATCH /photos/ update photos.update
DELETE /photos/ destroy photos.destroy

PHP native data types

Basic types

  • int, integer , string, array-key, bool, boolean, true, false, null, float, double, scalar, array, iterable, callable, resource, void, object

Array to query string

use Illuminate\Support\Arr;

$filters = [
    'location' => 'USA',
    'date_range'=>[
        'start' => '2023-01-01',
        'end' => '2020-12-31'
    ],
    'author'=>'John Doe'
];

$queryString = Arr::query($filters);
$url = 'https://example.com/?'.$queryString;

echo $url;

/** Output

    https://example.com/?location=USA&date_range[start]=2023-01-01&date_range[end]=2020-12-31&author=John Doe

 */

Relationships cheat table

Laravel Relationship Type From parent to child model From child to parent model Pivot Eloquent Model operations
HasOne/BelongsTo $parent->child()->save($child) $child->parent()->associate($parent) N/A
HasMany/BelongsTo $parent->children()->save($child) $child->parent()->associate($parent) N/A
BelongsToMany/BelongsToMany $parent->children()->attach($childId,$pivotData) $child->parents()->attach($parentId,$pivotData) Pivot::create([...])
MorphToMany/MorphToMany $parent->children()->attach($childId,$pivotData) $child->parents()->attach($parentId,$pivotData) Pivot::create([...])
Polymorphic (one-to-one) $parent->image()->save($image) $image->imageable()->associate($parent) N/A
Polymorphic (many-to-one) $parent->comments()->save($comment) $comment->commentable()->associate($parent) N/A
Polymorphic (many-to-many) $parent->tags()->attach($tagId,$pivotData) $tag->taggable()->attach($parentId,$pivotdata) Pivot:::create([...])

Default values in migrations


$table->string('name')->default('Untitled');

$table->string('total')->default(new Expression('(quantity * price)'));

$table->timestamp('order_date')->default(new Expression('NOW()'));

$table->integer('discount')->default(new Expression('(CASE WHEN quantity >= 10 THEN 10 ELSE 0 END)'));


Tailwind merge to PHP

// circle.blade.php
<div {{ $attributes->mergeClasses('w-10 h-10 rounded-full bg-red-500') }}>
</div>

// view.blade.php
<x-circle class='bg-blue-500' />

// output
<div class="w-10 h-10 rounded-full bg-blue-500"></div>

All Model.php attributes

protected $table = 'users'; // the table associated with the model

protected $primaryKey = 'uuid'; // The primary key for model

protected $keyType = 'int'; // The type of the primary key ID

protected $incrementing = true; // Indicates if the IDs should be auto-incrementing

protected $with = []; // The relationship to eager load on every query.

protected $withCount = []; // The relationship counts that should be eager on every query

protected $guarded = ['id']; // the attributes that are not mass assignable

protected $hidden = []; // attributes that should be hidden from array

protected $fillable = ['email','password']; // attributes that are mass assignable

protected $appends = ['field']; // The attrubutes that should be include in model

protected $fakeColumns = ['extras']; // The attrubutes that should be treated as fake columns

public $timestamps = false; // if the model should be timestamped

const CREATED_AT = 'createdAt'; // The name of the created_at col

const UPDATED_AT = 'updatedAt'; // The name of the updated_at col

protected $perpage = 25; // The number of models to return for pagination

protected $casts = [
    'assets' => 'array' // The attributes that should be cast to native types.
];

Custom Blade Conditionals

AppServiceProvider.php

// AppServiceProvider::boot()
Blade::if('writer',function(){
    return in_array(Auth::user()->role,['editor','reporter']);
});

view.blade.php


@writer
    //
@endwriter

Default to a relationship

class Comment extends Model
{
    public function author(){
        return $this->belongsTo(User::class)->withDefaults([
            'name' => 'Guest'
        ]);
    }
}

// Now in you view, instead of doing this
{{ $comment->author ? $comment->author->name : 'Guest' }}

// You can do this
{{ $comment->author->name  }}

Delted/Prune model data on schedule

class Order extends Model
{
    use Prunable;

    public function prunable(){
        return Order::query()
            ->whereStatus('abandoned')
            ->where('created_at','<=',now()->subMonth());
    }
}


// Console/Kernel.php
$schedule->command('model:prune')->daily();

whereNotNull()

$customers = Customer::query()
                ->whereNotNull(['payment_date','discount_cost'])
                ->get()

Do task after a model was created by factory

class UserFactory extends Factory
{
    public function definition(){
        // ...
    }

    public function configure():static
    {
        return $this->afterCreating(function (User $user){
            // Task after creating a user
            return $user->createTeam();
        });
    }
}

Saving a model and its relationship with push()


class User extends Model
{
    public function contact(){
        return $this->hasOne(Contact::class);
    }
}

$user = User::first();
$user->name = 'John Doe';
$user->contact->number = '112233445566';

$user->push(); // This will update both user and contact record in DB

Create route resource

Only include specified routes.


Route::resource('roles',RoleController::class)->only('update','index');

Start and End Data validation rule

$rules = [
    'start_date' => 'after:tomorrow',
    'end_date' => 'after:start_date'
];

Run a logic if a query takes a long time

AppServiceProvider.php

public function boot(){
    // Provide a handler to be invoked when a query executes longer than 300ms

    DB::whenQueryingForLongerThan(300,function ($connection, QueryExecuited $event){
        dump($event->sql);
        dump($event->binding);
        dump($event->time);
    });

    DB::allowQueryDurationHandlersToRunAgain();
}

// The handler will be invoked since the query takes longer
User::somethingThatTakeLongTime()->get();

Import classes in the same namespace

// Instead of this
use Illuminate\Support\Facaded\DB;
use Illuminate\Support\Facaded\Log;

// Do this
use Illuminate\Support\Facaded\{DB,Log};

Two ways of updating a model


Product::where('id',1)->update(['stock_left'=>1]);
// Result SQL query
// Update `products` set `stock_left` = 1 where `id` = 1

Product::find(1)->update(['stock_left'=>1]);
// Shorter code but 2 sql queries:
// - Select * from products where products.id = 1 limit 1
// - update products set stock_left = 1 where id = 1

Pint formatting Github action

name: PHP Linting

on: ['push', 'pull_request']

jobs:
  phplint:
    runs-on: ubuntu-latest

    steps:
      - name: checkout
        uses: actions/checkout@v3

      - name: 'laravel-pint'
        uses: aglipanci/[email protected]
        with:
          preset: laravel
          verboseMode: true
          testMode: true

Read duration Str macro

use Illuminate\Support\Str;

Str::macro('readDuration',funciton(...$text){
    $totalWords = str_word_count(implode("",$text));
    $minutesToRead = round($totalWords / 200);

    return (int)max(1,$minutesToRead);
});

echo Str::readDuration($post->text). ' min read';

Same relationship different param


// Get all clients related to this developer
public function clients(){
    return $this->belongsToMany(Clients::class);
}

// Get only local clients
public function clients(){
    return $this->belongsToMany(Clients::class)
            ->wherePivot('is_local',true);
}

Get columns of a table

DB::getSchemaBuilder()->getColumnListing('users');

// array (
//   0 => 'id',
//   1 => 'name',
//   2 => 'username',
//   3 => 'email',
//   4 => 'email_verified_at',
//   5 => 'password',
//   6 => 'remember_token',
//   7 => 'current_team_id',
//   8 => 'profile_photo_path',
//   9 => 'github_url',
//   10 => 'linkedin_url',
//   11 => 'deleted_at',
//   12 => 'created_at',
//   13 => 'updated_at',
//   14 => 'two_factor_secret',
//   15 => 'two_factor_recovery_codes',
//   16 => 'two_factor_confirmed_at',
//   17 => 'uuid',
// )

Optional model attributes

$user = User::find(1);

// This code would cause an error if $user is null or undefined
$address = $user->address; // NULL

// But when the optional() function, you can avoid the error;
$address = optional($user)->address;

Assign an re-use var in if condition


// Insted of repeating
if($this->option('type')){
    $stub = "/stub/contorller'.{$this->option('type')}.stub";
}

// assign and re-use the variable
if($type = $this->option('type')){
    $stub = "stub/controller.{$type}.stub";
}

Middleware in Controller


class MyController extends Controller
{
    public function getMiddleware(){
        return [
            [
                'middleware' => 'auth',
                'options' => []
            ]
        ];
    }
}

Clone all laravel docs locally

git clone laravel/docs laravel-docs

After cloning run it like any other project.

Two paginate in one view

$posts = Post::with('user')
            ->where('ai',false)
            ->latest()
            ->simplePaginate(perPage:10, pageName: 'postsPage');

$posts = Post::with('user')
            ->where('ai',true)
            ->latest()
            ->simplePaginate(perPage:10, pageName: 'aiPostsPage');

Show soft deleted data in route


Route::get('/users/{user}',function(User $user){
    return $user->email;
})->withTrashed();

Route::resource('users',UserController::class)
    ->withTrashed();

Route::resource('users',UserController::class)
    ->withTrashed(['shoe'])

Benchmark database queries

use App\Models\User;
use Illuminate\Support\Benchmark;

Benchmark::dd([
    'User count 1' => fn () => User::count(),
    'User count 2' => fn () => User::all()->count()
]);

// array:2 [ // vendor\laravel\framework\src\Illuminate\Support\Benchmark.php:48
//   "User count 1" => "14.129ms"
//   "User count 2" => "1.299ms"
// ]

Add Comment

Conversations (0)

SHTB

Building digital experiences and sharing knowledge through code and creativity.

Sign up for our newsletter

Stay up to date with the latest news and articles.

We care about the protection of your data. Read our Privacy Policy.

© 2026 Shahryar Tayeb. All rights reserved.