Laravel

The most popular full-stack web framework for PHP. Features Eloquent ORM and Blade templating engine with excellent development efficiency.

PHPFrameworkBackendWebEloquentArtisanMVC

GitHub Overview

laravel/laravel

Laravel is a web application framework with expressive, elegant syntax. We’ve already laid the foundation for your next big idea — freeing you to create without sweating the small things.

Stars81,516
Watchers4,403
Forks24,421
Created:June 8, 2011
Language:Blade
License:-

Topics

frameworklaravelphp

Star History

laravel/laravel Star History
Data as of: 7/16/2025, 08:43 AM

Framework

Laravel

Overview

Laravel is a modern PHP web application framework that enables high-quality web development with elegant syntax and rich functionality.

Details

Laravel was developed by Taylor Otwell in 2011 as a PHP web application framework. With the catchphrase "The PHP Framework for Web Artisans," it emphasizes beautiful and expressive syntax. Laravel adopts the Model-View-Controller (MVC) architectural pattern and provides powerful features including Eloquent ORM, Blade template engine, Artisan command-line tool, middleware, and dependency injection container. Standard features include authentication, routing, sessions, caching, database migrations, and unit testing, enabling rapid development. Through Composer package management, you can leverage a rich library ecosystem. Currently adopted by major enterprises like Disney+, Toyota, BMW, and Pfizer, it has become one of the most popular PHP frameworks.

Pros and Cons

Pros

  • Elegant Syntax: Beautiful and readable code
  • Rich Built-in Features: Many features like authentication, mail, queues built-in
  • Eloquent ORM: Intuitive and powerful database operations
  • Artisan CLI: Command-line tool that improves development efficiency
  • Blade Templates: Simple yet powerful template engine
  • Active Community: Large community and abundant learning resources
  • Excellent Documentation: Clear and detailed official documentation

Cons

  • Learning Curve: Difficult for beginners to master due to many features
  • Performance: Slightly heavier compared to other PHP frameworks
  • Version Compatibility: Breaking changes in major updates
  • Memory Usage: Large memory consumption in large-scale applications
  • Over-abstraction: Can become complex even for simple tasks

Key Links

Code Examples

Hello World

// Project creation commands
// composer create-project laravel/laravel hello-laravel
// cd hello-laravel
// php artisan serve

// routes/web.php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\WelcomeController;

// Basic route
Route::get('/', function () {
    return view('welcome', ['message' => 'Hello, Laravel World!']);
});

// Named route
Route::get('/hello', function () {
    return response()->json([
        'message' => 'Hello from Laravel API!',
        'timestamp' => now()->toDateTimeString(),
        'version' => app()->version()
    ]);
})->name('api.hello');

// Route using controller
Route::get('/welcome/{name?}', [WelcomeController::class, 'show'])
      ->name('welcome.show');

// app/Http/Controllers/WelcomeController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class WelcomeController extends Controller
{
    public function show(Request $request, $name = null)
    {
        $name = $name ?? 'Guest';
        
        return view('welcome.show', [
            'name' => $name,
            'time' => now()->format('F j, Y g:i A')
        ]);
    }
}

// resources/views/welcome/show.blade.php
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Laravel Welcome</title>
    <script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-gray-100">
    <div class="container mx-auto px-4 py-8">
        <div class="bg-white rounded-lg shadow-md p-6">
            <h1 class="text-3xl font-bold text-gray-800 mb-4">
                Welcome, {{ $name }}!
            </h1>
            <p class="text-gray-600 mb-4">Current time: {{ $time }}</p>
            <a href="{{ route('api.hello') }}" 
               class="bg-blue-500 text-white px-4 py-2 rounded hover:bg-blue-600">
                API Endpoint
            </a>
        </div>
    </div>
</body>
</html>

Eloquent ORM

// Model generation commands
// php artisan make:model User --migration --factory --seeder
// php artisan make:model Post --migration --factory
// php artisan make:model Tag --migration --factory
// php artisan make:model PostTag --migration

// app/Models/User.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class User extends Model
{
    use HasFactory, SoftDeletes;

    protected $fillable = [
        'name', 'email', 'password', 'active'
    ];

    protected $hidden = [
        'password', 'remember_token'
    ];

    protected $casts = [
        'email_verified_at' => 'datetime',
        'active' => 'boolean'
    ];

    // Relationships
    public function posts()
    {
        return $this->hasMany(Post::class);
    }

    public function publishedPosts()
    {
        return $this->hasMany(Post::class)->where('published', true);
    }

    // Scopes
    public function scopeActive($query)
    {
        return $query->where('active', true);
    }

    public function scopeHasPosts($query)
    {
        return $query->whereHas('posts');
    }

    // Accessors
    public function getFullNameAttribute()
    {
        return "{$this->first_name} {$this->last_name}";
    }

    // Mutators
    public function setEmailAttribute($value)
    {
        $this->attributes['email'] = strtolower($value);
    }
}

// app/Models/Post.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Post extends Model
{
    use HasFactory;

    protected $fillable = [
        'title', 'content', 'published', 'published_at', 'user_id'
    ];

    protected $casts = [
        'published' => 'boolean',
        'published_at' => 'datetime'
    ];

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

    public function tags()
    {
        return $this->belongsToMany(Tag::class, 'post_tags');
    }

    // Scopes
    public function scopePublished($query)
    {
        return $query->where('published', true);
    }

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

    public function scopeByTag($query, $tagName)
    {
        return $query->whereHas('tags', function ($q) use ($tagName) {
            $q->where('name', $tagName);
        });
    }

    // Accessors
    public function getExcerptAttribute()
    {
        return substr(strip_tags($this->content), 0, 150) . '...';
    }
}

// Eloquent usage examples
use App\Models\User;
use App\Models\Post;
use App\Models\Tag;

// Create data
$user = User::create([
    'name' => 'John',
    'email' => '[email protected]',
    'password' => bcrypt('password'),
    'active' => true
]);

$post = $user->posts()->create([
    'title' => 'Laravel Guide',
    'content' => 'Laravel is an amazing framework.',
    'published' => true,
    'published_at' => now()
]);

$tag = Tag::create(['name' => 'Laravel']);
$post->tags()->attach($tag);

// Query examples
$users = User::active()->with('posts')->get();
$posts = Post::published()
    ->with(['user', 'tags'])
    ->recent()
    ->paginate(10);

$laravelPosts = Post::byTag('Laravel')
    ->published()
    ->get();

// Advanced queries
$popularUsers = User::withCount(['posts' => function ($query) {
    $query->where('published', true);
}])
->having('posts_count', '>', 5)
->get();

// Bulk updates
Post::where('created_at', '<', now()->subDays(30))
    ->update(['archived' => true]);

// Creating relationships
$user = User::find(1);
$user->posts()->create([
    'title' => 'New Post',
    'content' => 'Content...'
]);

Routing

// routes/web.php
<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PostController;
use App\Http\Controllers\AdminController;
use App\Http\Controllers\Auth\LoginController;

// Basic routes
Route::get('/', function () {
    return view('home');
})->name('home');

Route::get('/about', function () {
    return view('about');
})->name('about');

// Routes with parameters
Route::get('/posts/{id}', function ($id) {
    $post = App\Models\Post::findOrFail($id);
    return view('posts.show', compact('post'));
})->name('posts.show')->where('id', '[0-9]+');

// Optional parameters
Route::get('/users/{id?}', function ($id = null) {
    if ($id) {
        $user = App\Models\User::findOrFail($id);
        return view('users.show', compact('user'));
    }
    return view('users.index');
})->name('users.index');

// RESTful resource routes
Route::resource('posts', PostController::class);

// Partial resource routes
Route::resource('comments', CommentController::class)
    ->only(['index', 'store', 'destroy']);

// Nested resources
Route::resource('posts.comments', CommentController::class)
    ->shallow();

// Route groups (middleware)
Route::middleware(['auth'])->group(function () {
    Route::get('/dashboard', function () {
        return view('dashboard');
    })->name('dashboard');

    Route::resource('posts', PostController::class)
        ->except(['index', 'show']);
});

// Groups with prefix
Route::prefix('admin')->name('admin.')->group(function () {
    Route::get('/dashboard', [AdminController::class, 'dashboard'])
        ->name('dashboard');
    Route::resource('users', AdminController::class);
});

// Subdomain routing
Route::domain('{subdomain}.example.com')->group(function () {
    Route::get('/', function ($subdomain) {
        return "Subdomain: {$subdomain}";
    });
});

// routes/api.php
Route::prefix('v1')->name('api.v1.')->group(function () {
    // Public APIs
    Route::get('/posts', [PostController::class, 'index']);
    Route::get('/posts/{post}', [PostController::class, 'show']);

    // Protected APIs
    Route::middleware('auth:sanctum')->group(function () {
        Route::post('/posts', [PostController::class, 'store']);
        Route::put('/posts/{post}', [PostController::class, 'update']);
        Route::delete('/posts/{post}', [PostController::class, 'destroy']);
    });
});

// Route model binding
Route::get('/posts/{post}', function (App\Models\Post $post) {
    return $post;
});

// Custom key model binding
Route::get('/posts/{post:slug}', function (App\Models\Post $post) {
    return $post;
});

// Route caching
// php artisan route:cache
// php artisan route:clear

Migrations and Seeders

// Migration generation commands
// php artisan make:migration create_posts_table
// php artisan make:migration add_published_to_posts_table --table=posts

// database/migrations/xxx_create_users_table.php
<?php

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

return new class extends Migration
{
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->boolean('active')->default(true);
            $table->rememberToken();
            $table->timestamps();
            $table->softDeletes();

            $table->index(['active', 'created_at']);
        });
    }

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

// database/migrations/xxx_create_posts_table.php
<?php

return new class extends Migration
{
    public function up()
    {
        Schema::create('posts', function (Blueprint $table) {
            $table->id();
            $table->string('title');
            $table->text('content');
            $table->string('slug')->unique();
            $table->boolean('published')->default(false);
            $table->timestamp('published_at')->nullable();
            $table->foreignId('user_id')->constrained()->onDelete('cascade');
            $table->timestamps();

            $table->index(['published', 'published_at']);
            $table->index('slug');
        });
    }

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

// Column addition migration
<?php

return new class extends Migration
{
    public function up()
    {
        Schema::table('posts', function (Blueprint $table) {
            $table->integer('view_count')->default(0)->after('published_at');
            $table->json('meta_data')->nullable()->after('view_count');
            $table->index('view_count');
        });
    }

    public function down()
    {
        Schema::table('posts', function (Blueprint $table) {
            $table->dropIndex(['view_count']);
            $table->dropColumn(['view_count', 'meta_data']);
        });
    }
};

// database/seeders/UserSeeder.php
<?php

namespace Database\Seeders;

use Illuminate\Database\Seeder;
use App\Models\User;
use Illuminate\Support\Facades\Hash;

class UserSeeder extends Seeder
{
    public function run()
    {
        // Create admin user
        User::create([
            'name' => 'Administrator',
            'email' => '[email protected]',
            'password' => Hash::make('password'),
            'active' => true
        ]);

        // Generate dummy data using factory
        User::factory(50)->create();
    }
}

// database/factories/PostFactory.php
<?php

namespace Database\Factories;

use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;

class PostFactory extends Factory
{
    public function definition()
    {
        $title = $this->faker->sentence();
        
        return [
            'title' => $title,
            'slug' => Str::slug($title),
            'content' => $this->faker->paragraphs(3, true),
            'published' => $this->faker->boolean(70),
            'published_at' => $this->faker->optional(0.7)->dateTimeBetween('-1 year', 'now'),
            'user_id' => User::factory(),
        ];
    }

    public function published()
    {
        return $this->state([
            'published' => true,
            'published_at' => now()
        ]);
    }

    public function draft()
    {
        return $this->state([
            'published' => false,
            'published_at' => null
        ]);
    }
}

// Migration execution commands
// php artisan migrate
// php artisan migrate:fresh --seed
// php artisan migrate:rollback
// php artisan migrate:status
// php artisan db:seed
// php artisan db:seed --class=UserSeeder

Form Processing and Validation

// FormRequest generation command
// php artisan make:request StorePostRequest

// app/Http/Requests/StorePostRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StorePostRequest extends FormRequest
{
    public function authorize()
    {
        return auth()->check();
    }

    public function rules()
    {
        return [
            'title' => 'required|string|max:255|unique:posts,title',
            'content' => 'required|string|min:50',
            'published' => 'boolean',
            'published_at' => 'nullable|date|after_or_equal:today',
            'tags' => 'array',
            'tags.*' => 'exists:tags,id',
            'featured_image' => 'nullable|image|mimes:jpeg,png,jpg|max:2048'
        ];
    }

    public function messages()
    {
        return [
            'title.required' => 'Title is required.',
            'title.unique' => 'This title is already taken.',
            'content.required' => 'Content is required.',
            'content.min' => 'Content must be at least 50 characters.',
            'featured_image.image' => 'Please select an image file.',
            'featured_image.max' => 'Image size must be under 2MB.'
        ];
    }

    public function attributes()
    {
        return [
            'title' => 'Title',
            'content' => 'Content',
            'published' => 'Published Status',
            'published_at' => 'Publish Date',
            'tags' => 'Tags',
            'featured_image' => 'Featured Image'
        ];
    }
}

// app/Http/Controllers/PostController.php
<?php

namespace App\Http\Controllers;

use App\Http\Requests\StorePostRequest;
use App\Models\Post;
use App\Models\Tag;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Storage;

class PostController extends Controller
{
    public function index()
    {
        $posts = Post::with(['user', 'tags'])
            ->published()
            ->latest()
            ->paginate(10);

        return view('posts.index', compact('posts'));
    }

    public function show(Post $post)
    {
        $post->load(['user', 'tags']);
        return view('posts.show', compact('post'));
    }

    public function create()
    {
        $tags = Tag::all();
        return view('posts.create', compact('tags'));
    }

    public function store(StorePostRequest $request)
    {
        $validated = $request->validated();
        $validated['slug'] = Str::slug($validated['title']);
        $validated['user_id'] = auth()->id();

        // Handle image upload
        if ($request->hasFile('featured_image')) {
            $validated['featured_image'] = $request->file('featured_image')
                ->store('posts', 'public');
        }

        $post = Post::create($validated);

        // Attach tags
        if (isset($validated['tags'])) {
            $post->tags()->sync($validated['tags']);
        }

        return redirect()
            ->route('posts.show', $post)
            ->with('success', 'Post created successfully.');
    }

    public function edit(Post $post)
    {
        $this->authorize('update', $post);
        $tags = Tag::all();
        return view('posts.edit', compact('post', 'tags'));
    }

    public function update(StorePostRequest $request, Post $post)
    {
        $this->authorize('update', $post);
        
        $validated = $request->validated();
        $validated['slug'] = Str::slug($validated['title']);

        // Handle new image upload
        if ($request->hasFile('featured_image')) {
            // Delete old image
            if ($post->featured_image) {
                Storage::disk('public')->delete($post->featured_image);
            }
            $validated['featured_image'] = $request->file('featured_image')
                ->store('posts', 'public');
        }

        $post->update($validated);

        // Update tag relationships
        if (isset($validated['tags'])) {
            $post->tags()->sync($validated['tags']);
        }

        return redirect()
            ->route('posts.show', $post)
            ->with('success', 'Post updated successfully.');
    }

    public function destroy(Post $post)
    {
        $this->authorize('delete', $post);
        
        // Delete image file
        if ($post->featured_image) {
            Storage::disk('public')->delete($post->featured_image);
        }

        $post->delete();

        return redirect()
            ->route('posts.index')
            ->with('success', 'Post deleted successfully.');
    }
}

Artisan Commands

// Custom command generation
// php artisan make:command ProcessPosts

// app/Console/Commands/ProcessPosts.php
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use App\Models\Post;
use App\Models\User;
use Illuminate\Support\Facades\Mail;

class ProcessPosts extends Command
{
    protected $signature = 'posts:process 
                           {--user= : Process only specific user}
                           {--days=30 : Days to process}
                           {--dry-run : Show results without actual processing}';

    protected $description = 'Process posts for periodic maintenance';

    public function handle()
    {
        $this->info('Starting post processing...');

        $days = $this->option('days');
        $userId = $this->option('user');
        $dryRun = $this->option('dry-run');

        // Initialize progress bar
        $query = Post::where('created_at', '<=', now()->subDays($days));
        
        if ($userId) {
            $query->where('user_id', $userId);
        }

        $posts = $query->get();
        $bar = $this->output->createProgressBar($posts->count());

        $processed = 0;
        $errors = 0;

        foreach ($posts as $post) {
            try {
                if (!$dryRun) {
                    // Actual processing
                    $this->processPost($post);
                }
                $processed++;
                
                if ($this->output->isVerbose()) {
                    $this->line("\nProcessed: {$post->title}");
                }
            } catch (\Exception $e) {
                $errors++;
                $this->error("\nError: {$post->title} - {$e->getMessage()}");
            }

            $bar->advance();
        }

        $bar->finish();

        // Display results
        $this->newLine(2);
        $this->info("Processing complete:");
        $this->table(
            ['Item', 'Count'],
            [
                ['Total', $posts->count()],
                ['Processed', $processed],
                ['Errors', $errors],
                ['Dry Run', $dryRun ? 'Yes' : 'No']
            ]
        );

        // User confirmation
        if ($errors > 0 && $this->confirm('Show error details?')) {
            $this->info('Please check error logs.');
        }

        return $errors > 0 ? 1 : 0;
    }

    private function processPost(Post $post)
    {
        // Post processing logic
        if (!$post->published && $post->created_at->diffInDays() > 30) {
            $post->delete();
            $this->warn("Deleted draft post: {$post->title}");
        }
    }
}

// Job creation and execution
// php artisan make:job SendNewsletterJob

// app/Jobs/SendNewsletterJob.php
<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use App\Models\User;
use App\Mail\Newsletter;
use Illuminate\Support\Facades\Mail;

class SendNewsletterJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $newsletter;
    protected $users;

    public function __construct($newsletter, $users)
    {
        $this->newsletter = $newsletter;
        $this->users = $users;
    }

    public function handle()
    {
        foreach ($this->users as $user) {
            Mail::to($user)->queue(new Newsletter($this->newsletter));
        }
    }
}

// Schedule configuration
// app/Console/Kernel.php
<?php

namespace App\Console;

use Illuminate\Console\Scheduling\Schedule;
use Illuminate\Foundation\Console\Kernel as ConsoleKernel;

class Kernel extends ConsoleKernel
{
    protected $commands = [
        Commands\ProcessPosts::class,
    ];

    protected function schedule(Schedule $schedule)
    {
        // Run daily at 2 AM
        $schedule->command('posts:process')->dailyAt('02:00');

        // Run weekly on Monday
        $schedule->command('posts:process --days=7')
                 ->weeklyOn(1, '03:00');

        // System maintenance
        $schedule->command('model:prune')->daily();
        $schedule->command('queue:work --stop-when-empty')->everyMinute();

        // Backup
        $schedule->command('backup:run')->daily();
    }

    protected function commands()
    {
        $this->load(__DIR__.'/Commands');

        require base_path('routes/console.php');
    }
}

// Artisan command execution
// php artisan posts:process
// php artisan posts:process --user=1 --days=7 --dry-run
// php artisan posts:process --help
// php artisan queue:work
// php artisan schedule:run
// php artisan schedule:list