Skip to content

🚀 Quick Reference Cheat Sheet

Essential patterns and templates for daily Laravel development. Bookmark this page for quick access!

📋 File Structure Quick Reference

app/
├── Actions/              # Single-purpose operations
├── Http/
│   ├── Controllers/      # Thin controllers
│   ├── Requests/         # Form validation
│   └── Resources/        # API responses
├── Models/               # Eloquent models
├── Services/             # Business logic
├── Repositories/         # Data access
│   └── Interfaces/       # Repository contracts
├── Observers/            # Model event handlers
└── Policies/             # Authorization logic

🎮 Controller Template

php
<?php

declare(strict_types=1);

namespace App\Http\Controllers\Api\V1;

use App\Http\Controllers\Controller;
use App\Http\Requests\StoreUserRequest;
use App\Http\Requests\UpdateUserRequest;
use App\Http\Resources\UserResource;
use App\Services\UserService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Resources\Json\AnonymousResourceCollection;

class UserController extends Controller
{
    public function __construct(
        private UserService $userService
    ) {}

    public function index(): AnonymousResourceCollection
    {
        $users = $this->userService->getAllUsers();
        return UserResource::collection($users);
    }

    public function store(StoreUserRequest $request): JsonResponse
    {
        $user = $this->userService->createUser($request->validated());
        
        return response()->json([
            'data' => new UserResource($user),
            'message' => 'User created successfully',
        ], 201);
    }

    public function show(int $id): JsonResponse
    {
        $user = $this->userService->getUserById($id);
        return response()->json(['data' => new UserResource($user)]);
    }

    public function update(UpdateUserRequest $request, int $id): JsonResponse
    {
        $user = $this->userService->updateUser($id, $request->validated());
        
        return response()->json([
            'data' => new UserResource($user),
            'message' => 'User updated successfully',
        ]);
    }

    public function destroy(int $id): JsonResponse
    {
        $this->userService->deleteUser($id);
        return response()->json(null, 204);
    }
}

🔧 Service Template

php
<?php

declare(strict_types=1);

namespace App\Services;

use App\Events\UserCreated;
use App\Exceptions\UserNotFoundException;
use App\Models\User;
use App\Repositories\Interfaces\UserRepositoryInterface;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Log;

class UserService
{
    public function __construct(
        private UserRepositoryInterface $userRepository
    ) {}

    public function getAllUsers(): Collection
    {
        return $this->userRepository->getAllActive();
    }

    public function getUserById(int $id): User
    {
        $user = $this->userRepository->find($id);
        
        if (!$user) {
            throw new UserNotFoundException("User with ID {$id} not found");
        }
        
        return $user;
    }

    public function createUser(array $data): User
    {
        try {
            DB::beginTransaction();

            $data['password'] = Hash::make(value: $data['password']);
            $data['email'] = strtolower(string: trim(string: $data['email']));

            $user = $this->userRepository->create(data: $data);

            event(event: new UserCreated($user));

            DB::commit();

            Log::info(message: 'User created successfully', context: ['user_id' => $user->id]);

            return $user;

        } catch (\Exception $e) {
            DB::rollBack();
            Log::error(message: 'Failed to create user', context: ['error' => $e->getMessage()]);
            throw $e;
        }
    }

    public function updateUser(int $id, array $data): User
    {
        $user = $this->getUserById(id: $id);

        if (isset($data['password'])) {
            $data['password'] = Hash::make(value: $data['password']);
        }

        $this->userRepository->update(id: $id, data: $data);

        return $user->refresh();
    }

    public function deleteUser(int $id): bool
    {
        $user = $this->getUserById(id: $id);
        return $this->userRepository->delete(id: $id);
    }
}

📦 Repository Template

php
<?php

declare(strict_types=1);

namespace App\Repositories;

use App\Models\User;
use App\Repositories\Interfaces\UserRepositoryInterface;
use Illuminate\Support\Collection;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;

class UserRepository implements UserRepositoryInterface
{
    public function __construct(
        private User $model
    ) {}

    public function find(int $id): ?User
    {
        return $this->model->find($id);
    }

    public function findByEmail(string $email): ?User
    {
        return $this->model->where(column: 'email', operator: '=', value: $email)->first();
    }

    public function create(array $data): User
    {
        return $this->model->create(attributes: $data);
    }

    public function update(int $id, array $data): bool
    {
        return $this->model->where(column: 'id', operator: '=', value: $id)->update(values: $data);
    }

    public function delete(int $id): bool
    {
        return $this->model->destroy(ids: $id) > 0;
    }

    public function getAllActive(): Collection
    {
        return $this->model
            ->where(column: 'is_active', operator: '=', value: true)
            ->with(relations: ['role'])
            ->orderBy(column: 'created_at', direction: 'desc')
            ->get();
    }

    public function paginate(int $perPage = 15): LengthAwarePaginator
    {
        return $this->model
            ->with(relations: ['role'])
            ->orderBy(column: 'created_at', direction: 'desc')
            ->paginate(perPage: $perPage);
    }
}

📝 Form Request Template

php
<?php

declare(strict_types=1);

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreUserRequest extends FormRequest
{
    public function authorize(): bool
    {
        return $this->user()->can('create', User::class);
    }

    public function rules(): array
    {
        return [
            'name' => ['required', 'string', 'max:255'],
            'email' => ['required', 'email', 'max:255', 'unique:users,email'],
            'password' => [
                'required',
                'string',
                'min:12',
                'regex:/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])/',
            ],
            'role' => ['required', 'string', 'in:user,admin,moderator'],
        ];
    }

    public function messages(): array
    {
        return [
            'password.regex' => 'Password must contain uppercase, lowercase, number, and special character.',
            'email.unique' => 'This email is already registered.',
        ];
    }

    protected function prepareForValidation(): void
    {
        $this->merge([
            'email' => strtolower(trim($this->email ?? '')),
            'name' => trim($this->name ?? ''),
        ]);
    }
}

📨 API Resource Template

Response Standards

For complete response format standards with macros and collections, see Response Macro Service Provider.

php
<?php

declare(strict_types=1);

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id' => $this->id,
            'name' => $this->name,
            'email' => $this->email,
            'role' => $this->role,
            'is_active' => $this->is_active,
            'email_verified_at' => $this->email_verified_at?->toIso8601String(),
            'created_at' => $this->created_at->toIso8601String(),
            'updated_at' => $this->updated_at->toIso8601String(),
            
            // Conditional relationships
            'profile' => ProfileResource::make($this->whenLoaded('profile')),
            'orders' => OrderResource::collection($this->whenLoaded('orders')),
            
            // Conditional fields
            'permissions' => $this->when(
                $request->user()?->isAdmin(),
                fn () => $this->permissions->pluck('name')
            ),
        ];
    }
}

⚡ Action Class Template

php
<?php

declare(strict_types=1);

namespace App\Actions\Users;

use App\Events\UserCreated;
use App\Models\User;
use App\Repositories\Interfaces\UserRepositoryInterface;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Hash;

class CreateUserAction
{
    public function __construct(
        private UserRepositoryInterface $userRepository
    ) {}

    public function execute(array $data): User
    {
        return DB::transaction(function () use ($data) {
            $data['password'] = Hash::make(value: $data['password']);
            $data['email'] = strtolower(string: trim(string: $data['email']));

            $user = $this->userRepository->create(data: $data);

            event(event: new UserCreated($user));

            return $user;
        });
    }
}

🗄️ Model Template

php
<?php

declare(strict_types=1);

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;

class Post extends Model
{
    use HasFactory, SoftDeletes;

    protected $fillable = [
        'title',
        'content',
        'user_id',
        'category_id',
        'is_published',
    ];

    protected $hidden = [
        'deleted_at',
    ];

    protected $casts = [
        'is_published' => 'boolean',
        'published_at' => 'datetime',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
    ];

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

    public function category(): BelongsTo
    {
        return $this->belongsTo(Category::class);
    }

    public function comments(): HasMany
    {
        return $this->hasMany(Comment::class);
    }

    public function scopePublished($query)
    {
        return $query->where(column: 'is_published', operator: '=', value: true);
    }

    public function scopeRecent($query)
    {
        return $query->orderBy(column: 'created_at', direction: 'desc');
    }
}

🔄 Migration Template

php
<?php

declare(strict_types=1);

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    public function up(): void
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->foreignId('user_id')->constrained()->cascadeOnDelete();
            $table->foreignId('category_id')->constrained()->cascadeOnDelete();
            $table->string('title');
            $table->text('content');
            $table->boolean('is_published')->default(false);
            $table->timestamp('published_at')->nullable();
            $table->timestamps();
            $table->softDeletes();
            
            // Indexes
            $table->index(['user_id', 'is_published']);
            $table->index('category_id');
            $table->index('created_at');
        });
    }

    public function down(): void
    {
        Schema::dropIfExists('posts');
    }
};

🧪 Test Templates

Unit Test

php
<?php

declare(strict_types=1);

namespace Tests\Unit\Services;

use App\Models\User;
use App\Repositories\Interfaces\UserRepositoryInterface;
use App\Services\UserService;
use Mockery;
use Tests\TestCase;

class UserServiceTest extends TestCase
{
    private UserService $userService;
    private UserRepositoryInterface $userRepository;

    protected function setUp(): void
    {
        parent::setUp();
        
        $this->userRepository = Mockery::mock(UserRepositoryInterface::class);
        $this->userService = new UserService($this->userRepository);
    }

    public function test_create_user_successfully(): void
    {
        // Arrange
        $userData = [
            'name' => 'John Doe',
            'email' => '[email protected]',
            'password' => 'password123',
        ];
        
        $expectedUser = new User($userData);
        
        $this->userRepository
            ->shouldReceive('create')
            ->once()
            ->andReturn($expectedUser);

        // Act
        $result = $this->userService->createUser($userData);

        // Assert
        $this->assertInstanceOf(User::class, $result);
        $this->assertEquals('John Doe', $result->name);
    }

    protected function tearDown(): void
    {
        Mockery::close();
        parent::tearDown();
    }
}

Feature Test

php
<?php

declare(strict_types=1);

namespace Tests\Feature;

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;

class UserManagementTest extends TestCase
{
    use RefreshDatabase, WithFaker;

    public function test_user_can_be_created(): void
    {
        // Arrange
        $userData = [
            'name' => $this->faker->name(),
            'email' => $this->faker->safeEmail(),
            'password' => 'SecurePass123!',
            'password_confirmation' => 'SecurePass123!',
        ];

        // Act
        $response = $this->postJson('/api/users', $userData);

        // Assert
        $response->assertStatus(201)
            ->assertJsonStructure([
                'data' => ['id', 'name', 'email'],
            ]);

        $this->assertDatabaseHas('users', [
            'name' => $userData['name'],
            'email' => $userData['email'],
        ]);
    }

    public function test_authenticated_user_can_view_profile(): void
    {
        $user = User::factory()->create();
        
        $response = $this->actingAs(user: $user)->getJson(uri: '/api/profile');

        $response->assertStatus(200)
            ->assertJson([
                'data' => [
                    'id' => $user->id,
                    'name' => $user->name,
                ],
            ]);
    }
}

🔐 Policy Template

php
<?php

declare(strict_types=1);

namespace App\Policies;

use App\Models\Post;
use App\Models\User;

class PostPolicy
{
    public function viewAny(User $user): bool
    {
        return true;
    }

    public function view(User $user, Post $post): bool
    {
        return $post->is_published || $post->user_id === $user->id;
    }

    public function create(User $user): bool
    {
        return $user->hasPermission('posts.create');
    }

    public function update(User $user, Post $post): bool
    {
        return $user->id === $post->user_id 
            || $user->hasPermission('posts.update.any');
    }

    public function delete(User $user, Post $post): bool
    {
        return $user->id === $post->user_id 
            || $user->hasPermission('posts.delete.any');
    }
}

👁️ Observer Template

php
<?php

declare(strict_types=1);

namespace App\Observers;

use App\Models\User;
use Illuminate\Support\Facades\Log;

class UserObserver
{
    public function created(User $user): void
    {
        Log::info(message: 'User created', context: ['user_id' => $user->id]);
    }

    public function updated(User $user): void
    {
        if ($user->wasChanged(attributes: 'email')) {
            Log::info(message: 'User email changed', context: [
                'user_id' => $user->id,
                'old_email' => $user->getOriginal(key: 'email'),
                'new_email' => $user->email,
            ]);
        }
    }

    public function deleted(User $user): void
    {
        Log::info(message: 'User deleted', context: ['user_id' => $user->id]);
    }
}

🎯 Common Artisan Commands

bash
# Generate files
php artisan make:controller UserController --api --requests
php artisan make:model Post -mfs  # Migration, Factory, Seeder
php artisan make:request StoreUserRequest
php artisan make:resource UserResource
php artisan make:policy PostPolicy --model=Post
php artisan make:observer UserObserver --model=User
php artisan make:service UserService  # Custom command
php artisan make:repository UserRepository  # Custom command
php artisan make:action CreateUserAction  # Custom command

# Database
php artisan migrate
php artisan migrate:rollback
php artisan migrate:fresh --seed
php artisan db:seed

# Testing
php artisan test
php artisan test --coverage
php artisan test --filter UserTest

# Code quality
./vendor/bin/pint
./vendor/bin/phpstan analyse
php artisan optimize
php artisan optimize:clear

# Cache
php artisan cache:clear
php artisan config:clear
php artisan route:clear
php artisan view:clear

📊 Common Validation Rules

php
// String validation
'name' => 'required|string|max:255|min:3'
'email' => 'required|email|unique:users,email|max:255'
'url' => 'required|url|active_url'
'slug' => 'required|alpha_dash|unique:posts,slug'

// Numeric validation
'age' => 'required|integer|min:18|max:120'
'price' => 'required|numeric|min:0|max:999999.99'
'quantity' => 'required|integer|between:1,100'

// Date validation
'birth_date' => 'required|date|before:today'
'start_date' => 'required|date|after_or_equal:today'
'end_date' => 'required|date|after:start_date'

// File validation
'avatar' => 'required|image|mimes:jpg,png|max:2048'
'document' => 'required|file|mimes:pdf,doc,docx|max:10240'

// Array validation
'tags' => 'required|array|min:1|max:5'
'tags.*' => 'required|string|distinct|exists:tags,name'

// Boolean validation
'is_active' => 'required|boolean'
'accept_terms' => 'required|accepted'

// Relation validation
'user_id' => 'required|integer|exists:users,id'
'category_id' => 'required|integer|exists:categories,id'

// Password validation
'password' => [
    'required',
    'string',
    'min:12',
    'regex:/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])/',
    'confirmed'
]

🔄 Query Optimization Patterns

php
// N+1 Prevention
$users = User::with(['posts', 'profile'])->get();
$users = User::with(['posts' => fn($q) => $q->published()])->get();

// Select specific columns
$users = User::select(['id', 'name', 'email'])->get();
$users = User::with(['posts:id,user_id,title'])->get();

// Pagination
$users = User::paginate(15);
$users = User::simplePaginate(15);
$users = User::cursorPaginate(15);

// Chunking
User::chunk(100, function ($users) {
    foreach ($users as $user) {
        // Process user
    }
});

// Lazy loading
User::lazy()->each(function ($user) {
    // Process user
});

🎨 Response Format Standards

php
// Success response
return response()->json([
    'data' => $resource,
    'message' => 'Operation successful',
], 200);

// Created response
return response()->json([
    'data' => $resource,
    'message' => 'Resource created successfully',
], 201);

// Error response
return response()->json([
    'error' => [
        'message' => 'Resource not found',
        'code' => 'RESOURCE_NOT_FOUND',
    ],
], 404);

// Validation error response
return response()->json([
    'error' => [
        'message' => 'Validation failed',
        'errors' => $validator->errors(),
    ],
], 422);

💡 Pro Tip: Keep this page bookmarked for quick access during development. Use Ctrl+F to quickly find specific templates!

Built with VitePress