Want real confidence building Laravel apps, not just watching tutorials? This post gives you 100 Laravel practice problems with clear, step-by-step solutions. You’ll work through routing, controllers, Blade, Eloquent, migrations, forms, middleware, and APIs. Each problem is explained simply — try it first, then check the answer. Perfect for beginners and interview prep. Pick a challenge and start mastering Laravel today.
Try it: 100 PHP practice problems with solutions
1. Create a route that responds to /hello with the text “Welcome to Laravel”.
php
Route::get('/hello', function () {
return 'Welcome to Laravel';
});
2. Create a route that accepts a name parameter and returns “Hello, {name}”.
php
Route::get('/hello/{name}', function ($name) {
return "Hello, $name";
});
3. Create a route /sum/{a}/{b} that returns the sum of two numbers.
php
Route::get('/sum/{a}/{b}', function ($a, $b) {
return $a + $b;
});
4. Create a controller UserController with a method index that returns “List of users”.
php
php artisan make:controller UserController
php
// app/Http/Controllers/UserController.php
namespace App\Http\Controllers;
class UserController extends Controller
{
public function index()
{
return 'List of users';
}
}
5. Register a route that calls the index method of UserController.
php
Route::get('/users', [UserController::class, 'index']);
6. Create a GET route /profile that returns a view profile.blade.php with a variable name.
php
Route::get('/profile', function () {
return view('profile', ['name' => 'John Doe']);
});
blade
<!-- resources/views/profile.blade.php -->
<h1>Profile of {{ $name }}</h1>
7. Create a POST route /submit that accepts form data and returns the submitted name.
php
Route::post('/submit', function (\Illuminate\Http\Request $request) {
return 'Submitted: ' . $request->input('name');
});
8. Use route name for the /user/profile route and generate a URL using the route helper.
php
Route::get('/user/profile', function () {
return route('profile');
})->name('profile');
9. Create a route group with prefix admin and middleware auth.
php
Route::prefix('admin')->middleware('auth')->group(function () {
Route::get('/dashboard', function () {
return 'Admin dashboard';
});
});
10. Create a resource controller PostController with all resourceful methods.
bash
php artisan make:controller PostController --resource
11. Register the resourceful route for PostController.
php
Route::resource('posts', PostController::class);
12. Generate a migration for a products table with columns: name, price, description.
bash
php artisan make:migration create_products_table
php
// database/migrations/xxxx_xx_xx_create_products_table.php
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->decimal('price', 8, 2);
$table->text('description')->nullable();
$table->timestamps();
});
}
13. Run all pending migrations.
bash
php artisan migrate
14. Create a model Product with fillable fields name, price, description.
bash
php artisan make:model Product -m
php
// app/Models/Product.php protected $fillable = ['name', 'price', 'description'];
15. Use Eloquent to insert a new product into the database.
php
Product::create([
'name' => 'Laptop',
'price' => 999.99,
'description' => 'High performance laptop'
]);
16. Retrieve all products from the database and return as JSON.
php
$products = Product::all(); return response()->json($products);
17. Update a product with id=1, change its price to 899.99.
php
$product = Product::find(1); $product->price = 899.99; $product->save();
18. Delete a product with id=2.
php
Product::destroy(2);
19. Create a form request StoreProductRequest with validation rules: name required, price numeric.
bash
php artisan make:request StoreProductRequest
php
// app/Http/Requests/StoreProductRequest.php
public function rules()
{
return [
'name' => 'required|string|max:255',
'price' => 'required|numeric|min:0',
];
}
20. Use the form request in a controller method to store a product.
php
use App\Http\Requests\StoreProductRequest;
public function store(StoreProductRequest $request)
{
$product = Product::create($request->validated());
return redirect()->route('products.index');
}
21. Create a custom validation rule that ensures a field is uppercase.
php
use Illuminate\Support\Facades\Validator;
Validator::extend('uppercase', function ($attribute, $value, $parameters, $validator) {
return strtoupper($value) === $value;
});
22. Use the unique validation rule on a email field during user registration.
php
'email' => 'required|email|unique:users,email'
23. Display validation errors in a Blade view.
blade
@if ($errors->any())
<div class="alert alert-danger">
<ul>
@foreach ($errors->all() as $error)
<li>{{ $error }}</li>
@endforeach
</ul>
</div>
@endif
24. Create a Blade layout layouts/app.blade.php with a yield section content.
blade
<!-- resources/views/layouts/app.blade.php -->
<html>
<head><title>App</title></head>
<body>
@yield('content')
</body>
</html>
25. Extend the layout in a child view and define the content section.
blade
@extends('layouts.app')
@section('content')
<h1>Welcome</h1>
@endsection
26. Use a Blade component named alert that accepts a type prop (success, error).
bash
php artisan make:component Alert
blade
<!-- resources/views/components/alert.blade.php -->
<div class="alert alert-{{ $type }}">
{{ $slot }}
</div>
php
// app/View/Components/Alert.php
public $type;
public function __construct($type = 'info')
{
$this->type = $type;
}
blade
<x-alert type="success">Operation successful!</x-alert>
27. Create a middleware CheckAge that blocks access if age < 18.
bash
php artisan make:middleware CheckAge
php
// app/Http/Middleware/CheckAge.php
public function handle($request, $next)
{
if ($request->input('age') < 18) {
return redirect('home');
}
return $next($request);
}
28. Register the middleware globally in app/Http/Kernel.php.
php
protected $routeMiddleware = [
'check.age' => \App\Http\Middleware\CheckAge::class,
];
29. Apply the check.age middleware to a route group.
php
Route::middleware(['check.age'])->group(function () {
Route::get('/adults-only', function () {
return 'Welcome adult';
});
});
30. Use Eloquent’s where clause to get products with price > 100.
php
$expensive = Product::where('price', '>', 100)->get();
31. Use Eloquent’s orderBy to sort products by name descending.
php
$sorted = Product::orderBy('name', 'desc')->get();
32. Use the with method to eager load a relationship (e.g., posts on a User model).
php
$users = User::with('posts')->get();
33. Define a one‑to‑many relationship posts on User model.
php
// app/Models/User.php
public function posts()
{
return $this->hasMany(Post::class);
}
34. Define the inverse one‑to‑many relationship user on Post model.
php
// app/Models/Post.php
public function user()
{
return $this->belongsTo(User::class);
}
35. Create a seeder that inserts 10 random users into the database.
bash
php artisan make:seeder UserSeeder
php
// database/seeders/UserSeeder.php
public function run()
{
\App\Models\User::factory(10)->create();
}
36. Run the seeder.
bash
php artisan db:seed --class=UserSeeder
37. Use database transactions to safely update a product and its inventory.
php
use Illuminate\Support\Facades\DB;
DB::transaction(function () {
$product = Product::find(1);
$product->price = 199;
$product->save();
Inventory::where('product_id', 1)->decrement('quantity', 1);
});
38. Create a query scope active in the Product model that returns products with status = active.
php
// app/Models/Product.php
public function scopeActive($query)
{
return $query->where('status', 'active');
}
39. Use the active scope to retrieve active products.
php
$activeProducts = Product::active()->get();
40. Use Laravel’s query builder to perform a raw SQL select.
php
$results = DB::select('SELECT * FROM products WHERE price > ?', [50]);
41. Create a custom artisan command SendEmails.
bash
php artisan make:command SendEmails
php
// app/Console/Commands/SendEmails.php
protected $signature = 'emails:send {user}';
public function handle()
{
$user = User::find($this->argument('user'));
$this->info("Sending email to {$user->email}");
}
42. Register the command and call it via php artisan emails:send 1.
It is automatically registered after creation; just run php artisan emails:send 1.
43. Schedule a task to run daily at midnight (e.g., prune old records).
php
// app/Console/Kernel.php
protected function schedule(Schedule $schedule)
{
$schedule->command('records:prune')->daily();
}
44. Use the artisan tinker REPL to retrieve the first product.
bash
php artisan tinker >>> App\Models\Product::first();
45. Create an event OrderShipped and its listener SendShipmentNotification.
bash
php artisan make:event OrderShipped php artisan make:listener SendShipmentNotification --event OrderShipped
php
// app/Events/OrderShipped.php // app/Listeners/SendShipmentNotification.php
46. Dispatch the OrderShipped event after an order is updated.
php
event(new OrderShipped($order));
47. Create a notification class InvoicePaid that sends an email.
bash
php artisan make:notification InvoicePaid
php
// app/Notifications/InvoicePaid.php
public function via($notifiable)
{
return ['mail'];
}
public function toMail($notifiable)
{
return (new MailMessage)->line('Your invoice has been paid.');
}
48. Send the notification to a user.
php
$user->notify(new InvoicePaid());
49. Use Laravel’s built‑in authentication scaffolding (UI) for login/register.
bash
composer require laravel/ui php artisan ui bootstrap --auth npm install && npm run dev
50. Protect a route with the auth middleware.
php
Route::get('/dashboard', function () {
return view('dashboard');
})->middleware('auth');
51. Get the currently authenticated user’s ID in a controller.
php
$userId = auth()->id();
52. Hash a password using the Hash facade before storing.
php
use Illuminate\Support\Facades\Hash;
$hashed = Hash::make('plain-text-password');
53. Verify a plain password against a hashed one.
php
if (Hash::check('plain-text-password', $hashed)) {
// correct
}
Try it: 100 MySQL practice problems with solutions
54. Create a policy for the Post model to restrict update to the owner.
bash
php artisan make:policy PostPolicy --model=Post
php
// app/Policies/PostPolicy.php
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
55. Authorize the update action in a controller using the policy.
php
$this->authorize('update', $post);
56. Use pagination on a product list (10 per page).
php
$products = Product::paginate(10);
blade
{{ $products->links() }}
57. Implement soft deletes for the Product model.
bash
php artisan make:migration add_soft_deletes_to_products_table
php
// migration: $table->softDeletes(); // Model: use SoftDeletes;
58. Retrieve trashed (soft-deleted) products.
php
$trashed = Product::onlyTrashed()->get();
59. Restore a soft-deleted product.
php
$product = Product::withTrashed()->find(5); $product->restore();
60. Use Laravel’s env() helper to read the APP_NAME configuration.
php
$appName = env('APP_NAME', 'Laravel');
61. Create a custom helper function formatPrice that adds currency symbol.
php
// app/Helpers/helpers.php
if (! function_exists('formatPrice')) {
function formatPrice($price)
{
return '$' . number_format($price, 2);
}
}
62. Autoload the helpers file via composer.json.
json
"autoload": {
"files": ["app/Helpers/helpers.php"]
}
63. Use Redis to cache a product query for 60 seconds.
php
use Illuminate\Support\Facades\Cache;
$product = Cache::remember('product.1', 60, function () {
return Product::find(1);
});
64. Use the cache helper to store a value permanently.
php
cache(['key' => 'value']);
65. Create a job SendWelcomeEmail and dispatch it on the queue.
bash
php artisan make:job SendWelcomeEmail
php
dispatch(new SendWelcomeEmail($user));
66. Run the queue worker to process jobs.
bash
php artisan queue:work
67. Use Laravel’s Str helper to generate a random string of length 10.
php
use Illuminate\Support\Str; $random = Str::random(10);
68. Use Collection methods to filter and map data.
php
$filtered = Product::all()->filter(function ($product) {
return $product->price > 100;
})->map(function ($product) {
return $product->name;
});
Try it: CSS practice problems with solutions
69. Create a database index on products.name column via a migration.
php
Schema::table('products', function (Blueprint $table) {
$table->index('name');
});
70. Use lazy or chunk to process large data without memory issues.
php
Product::chunk(100, function ($products) {
foreach ($products as $product) {
// process
}
});
71. Create a scheduled artisan command that sends a weekly report every Monday.
php
$schedule->command('report:weekly')->mondays()->at('08:00');
72. Use Laravel’s local scope to get products with stock > 0.
php
public function scopeInStock($query)
{
return $query->where('stock', '>', 0);
}
73. Use the firstOrCreate method to find a user by email or create new one.
php
$user = User::firstOrCreate(
['email' => 'john@example.com'],
['name' => 'John Doe', 'password' => bcrypt('secret')]
);
74. Create a many‑to‑many relationship between User and Role with pivot table.
php
// User model
public function roles()
{
return $this->belongsToMany(Role::class);
}
75. Sync roles for a user (assign role IDs 1,2,3).
php
$user->roles()->sync([1,2,3]);
76. Use withCount to get the number of posts for each user.
php
$users = User::withCount('posts')->get();
foreach ($users as $user) {
echo $user->posts_count;
}
77. Handle SQL exceptions using custom try‑catch.
php
try {
DB::insert('insert into products (name) values (?)', ['Laptop']);
} catch (\Illuminate\Database\QueryException $e) {
if ($e->getCode() == 23000) {
// Duplicate entry
}
}
78. Create a custom error page for 404 (resources/views/errors/404.blade.php).
blade
<!-- resources/views/errors/404.blade.php --> <h1>Page not found</h1> <p>The requested page does not exist.</p>
79. Use config helper to define and retrieve a custom configuration settings.timezone.
php
// config/settings.php return ['timezone' => 'UTC'];
php
$tz = config('settings.timezone');
80. Use service container to bind an interface to a concrete implementation.
php
use App\Contracts\PaymentGateway; use App\Services\StripeGateway; $this->app->bind(PaymentGateway::class, StripeGateway::class);
81. Resolve a class from the service container by type‑hinting in a controller constructor.
php
public function __construct(PaymentGateway $gateway)
{
$this->gateway = $gateway;
}
82. Create a global middleware that logs every request URL and method.
php
// app/Http/Middleware/LogRequest.php
public function handle($request, $next)
{
\Log::info($request->method() . ' ' . $request->fullUrl());
return $next($request);
}
83. Register the middleware as web group middleware in Kernel.php.
php
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\LogRequest::class,
],
];
84. Use route helper to generate absolute URL for named route product.show with parameter id.
php
$url = route('product.show', ['id' => 5]);
85. Create a signed URL that expires in 30 minutes for a route invoice.download.
php
$url = URL::temporarySignedRoute('invoice.download', now()->addMinutes(30), ['id' => 1]);
86. Verify a signed request in the controller using hasValidSignature middleware.
php
Route::get('/invoice/{id}/download', function ($id) {
// ...
})->middleware('signed')->name('invoice.download');
87. Use Storage facade to upload a file to the public disk.
php
use Illuminate\Support\Facades\Storage;
$path = Storage::disk('public')->putFile('uploads', $request->file('avatar'));
88. Generate a symbolic link for public/storage to storage/app/public.
bash
php artisan storage:link
89. Create a mail class OrderShipped and send it.
bash
php artisan make:mail OrderShipped
php
Mail::to($user->email)->send(new OrderShipped($order));
90. Use markdown mail template for the OrderShipped mail.
php
public function build()
{
return $this->markdown('emails.orders.shipped');
}
91. Use the env file to set QUEUE_CONNECTION=database and create the jobs table.
bash
php artisan queue:table php artisan migrate
92. Specify the queue name high when dispatching a job.
php
dispatch((new ProcessPodcast)->onQueue('high'));
93. Use dispatchAfterResponse to run a job after the HTTP response is sent.
php
dispatchAfterResponse(new SendNotification);
94. Create a custom validation rule object Uppercase.
bash
php artisan make:rule Uppercase
php
app/Rules/Uppercase.php
public function passes($attribute, $value)
{
return strtoupper($value) === $value;
}
public function message()
{
return 'The :attribute must be uppercase.';
}
95. Use the custom rule in a validator.
php
use App\Rules\Uppercase; 'code' => ['required', new Uppercase]
96. Use lazyLoading detection to identify N+1 queries.
php
// In AppServiceProvider Model::preventLazyLoading(! app()->isProduction());
97. Use dd (dump and die) to inspect a variable.
php
dd(Product::all());
98. Create a singleton binding in the service container that returns the same instance each time.
php
$this->app->singleton(SomeService::class, function ($app) {
return new SomeService($app->make(Config::class));
});
99. Use throw_unless helper to throw an exception unless condition is true.
php
throw_unless($user->isAdmin(), AuthorizationException::class);
Try it: 100 Javascript practice problems with solutions
100. Deploy a Laravel application by optimizing the configuration and caching routes.
bash
php artisan config:cache php artisan route:cache php artisan view:cache
Final Thought
You did it — 100 Laravel problems conquered! Can you feel that electric buzz? That’s the thrill of knowing you didn’t just study Laravel, you built with it! Every route you mapped, every controller you crafted, every Eloquent query you finessed — it all adds up to one undeniable truth: you’re a Laravel developer now, and nothing can stop you!
Think about how far you’ve come! From simple Blade views to full API endpoints, you’ve unlocked level after level like a coding superhero. The magic of Laravel is no longer a mystery — it’s your playground! Every new project, every client, every job interview is about to meet a version of you that’s sharper, faster, and bursting with confidence.
Don’t let the momentum fade! Take this fire and build that dream app you’ve been thinking about. Tackle an even bigger challenge. Bookmark this page as your personal trophy cabinet — proof that you can master anything you set your mind to. The web is waiting for what you’ll create next! Go build, go shine, and keep that joyful Laravel spark alive!