- Database Interaction
- Middleware
- Caching
- Events
- Logging
- Commands
- Notifications
- API Responses
- Blade Templates
- Direct querying in Blade files
- Using
echo
in Blade files - Eloquent Relationships
- Testing
- Direct SQL Queries in Controllers
- Database Querying
- Validation
- Security Concerns
- Error Handling
- File Uploads
- User model
- Hardcoding configuration values
- Not using Route Model Binding
- Hardcoding Dependencies instead of using Dependency Injection
- Hardcoding configurations
- Mass assignment without guarded fields
- Lack of pagination for large datasets
- Use config and language files, constants instead of text in the code
- Use Constants for Repeated Values
- API Rate Limiting
- Form Input Sanitazation
- Custom Helpers
- Avoid Duplicate Queries
- Testing Practices
- Service Container Binding
- Repository Pattern
- Using Static Methods
- Queue Jobs
- Best Practices accepted by community
- Laravel Naming Conventions
- Interview Questions
class ProductController extends Controller
{
public function show()
{
$products = DB::table('products')->where('active', 1)->get();
return view('products.index', ['products' => $products]);
}
}
use App\Models\Product;
class ProductController extends Controller
{
public function index()
{
$products = Product::active()->get();
return view('products.index', compact('products'));
}
}
class UserController extends Controller
{
public function index()
{
// Query the database directly in the controller
$users = DB::table('users')->get();
return view('users.index', compact('users'));
}
public function store(Request $request)
{
// No validation, direct database insertion
DB::table('users')->insert([
'name' => $request->input('name'),
'email' => $request->input('email'),
'password' => bcrypt($request->input('password')),
]);
return redirect()->route('users.index');
}
}
class UserController extends Controller
{
public function index()
{
// Use Eloquent model to fetch users
$users = User::all();
return view('users.index', compact('users'));
}
public function store(UserRequest $request)
{
// Validation logic is handled through a custom Form Request class
User::create([
'name' => $request->name,
'email' => $request->email,
'password' => bcrypt($request->password),
]);
return redirect()->route('users.index');
}
}
public function handle($request, Closure $next)
{
if (Auth::user()->role !== 'admin') {
return response('Unauthorized.', 403);
}
return $next($request);
}
public function handle($request, Closure $next)
{
if (!Auth::user() || !Auth::user()->hasRole('admin')) {
abort(403, 'Unauthorized action.');
}
return $next($request);
}
$products = DB::table('products')->get();
Cache::put('products', $products, 3600);
$products = Cache::remember('products', 3600, function () {
return Product::all();
});
public function store(Request $request)
{
$user = User::create($request->validated());
Mail::to($user->email)->send(new WelcomeMail($user));
}
public function store(Request $request)
{
$user = User::create($request->validated());
event(new UserRegistered($user));
}
Event Listener:
public function handle(UserRegistered $event)
{
Mail::to($event->user->email)->send(new WelcomeMail($event->user));
}
Log::info('Something went wrong: ' . $e->getMessage());
Log::error('Exception encountered.', ['error' => $e->getMessage(), 'trace' => $e->getTraceAsString()]);
public function handle()
{
DB::table('orders')->where('status', 'pending')->delete();
}
public function handle()
{
Order::pending()->delete();
}
Mail::to($user->email)->send(new ResetPasswordMail($token));
$user->notify(new ResetPasswordNotification($token));
return response()->json(['data' => $data], 200);
return response()->json([
'status' => 'success',
'data' => $data,
], 200);
@if ($user->role == 'admin')
<p>Welcome Admin</p>
@endif
@can('viewAdminDashboard', $user)
<p>Welcome Admin</p>
@endcan
<h1>Users</h1>
@foreach (User::all() as $user)
<p>{{ $user->name }}</p>
@endforeach
Controller
public function index()
{
$users = User::all();
return view('users.index', compact('users'));
}
Blade
<h1>Users</h1>
@foreach ($users as $user)
<p>{{ $user->name }}</p>
@endforeach
<p><?php echo $user->name; ?></p>
<p>{{ $user->name }}</p>
<p>{{ $user->name ?? 'Guest' }}</p>
$comments = DB::table('comments')->where('post_id', $postId)->get();
$comments = $post->comments;
public function testExample()
{
$this->get('/home')->assertStatus(200);
}
public function testHomePageLoadsCorrectly()
{
$this->get('/home')
->assertStatus(200)
->assertSee('Welcome')
->assertDontSee('Error');
}
public function index()
{
$users = DB::select('SELECT * FROM users');
return response()->json($users);
}
use App\Models\User;
public function index()
{
$users = User::all();
return response()->json($users);
}
// Direct query execution without optimization
$users = DB::table('users')
->join('orders', 'users.id', '=', 'orders.user_id')
->where('orders.created_at', '>', now()->subMonth())
->select('users.name', 'orders.total')
->get();
class UserController extends Controller
{
public function index()
{
// Use Eloquent relationships and eager loading
$users = User::with('orders')->whereHas('orders', function($query) {
$query->where('created_at', '>', now()->subMonth());
})->get();
return view('users.index', compact('users'));
}
}
public function store(Request $request)
{
// No validation, using raw request data
$user = new User;
$user->name = $request->input('name');
$user->email = $request->input('email');
$user->password = bcrypt($request->input('password'));
$user->save();
}
class UserRequest extends FormRequest
{
public function rules()
{
return [
'name' => 'required|string|max:255',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|min:8|confirmed',
];
}
}
Controller
public function store(UserRequest $request)
{
$user = User::create($request->validated());
}
public function login(Request $request)
{
$user = User::where('email', $request->email)->first();
if ($user && Hash::check($request->password, $user->password)) {
Auth::login($user);
return redirect()->route('dashboard');
}
return back()->withErrors(['email' => 'Invalid credentials']);
}
public function login(Request $request)
{
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials)) {
return redirect()->route('dashboard');
}
return back()->withErrors(['email' => 'Invalid credentials']);
}
public function show($id)
{
$user = User::find($id);
if (!$user) {
return response('User not found', 404);
}
return view('users.show', compact('user'));
}
public function show($id)
{
$user = User::findOrFail($id);
return view('users.show', compact('user'));
}
public function upload(Request $request)
{
$request->file('image')->move('uploads', 'image.jpg');
}
public function upload(Request $request)
{
$request->validate([
'image' => 'required|image|mimes:jpeg,png,jpg,gif|max:2048',
]);
$path = $request->file('image')->store('uploads', 'public');
return response()->json(['path' => $path]);
}
public function getFullNameLong(): string
{
return 'Mr. ' . $this->first_name . ' ' . $this->middle_name . ' ' . $this->last_name;
}
public function getFullNameLong(): string
{
return $this->title . ' ' . $this->first_name . ' ' . $this->middle_name . ' ' . $this->last_name;
}
public function getFullNameLong(): string
{
return $this->title . ' ' . ($this->first_name ?? '') . ' ' . ($this->middle_name ?? '') . ' ' . ($this->last_name ?? '');
}
public function getFullNameShort(): string
{
return $this->first_name[0] . '. ' . $this->last_name;
}
public function getFullNameShort(): string
{
$firstNameInitial = !empty($this->first_name) ? $this->first_name[0] . '.' : '';
return $firstNameInitial . ' ' . $this->last_name;
}
public function sendEmail()
{
$to = '[email protected]';
$subject = 'Hello World';
mail($to, $subject, 'This is a test email.');
}
use Illuminate\Support\Facades\Mail;
public function sendEmail()
{
Mail::to(config('mail.default_to_address'))->send(new App\Mail\WelcomeMail());
}
public function show($id)
{
$user = User::find($id);
if (!$user) {
abort(404);
}
return view('user.show', compact('user'));
}
public function show(User $user)
{
return view('user.show', compact('user'));
}
public function sendNotification()
{
$mailer = new \App\Services\Mailer();
$mailer->send('Hello World');
}
use App\Services\Mailer;
public function sendNotification(Mailer $mailer)
{
$mailer->send('Hello World');
}
$apiKey = '12345'; // API key hardcoded
$apiKey = config('services.api.key');
public function uploadFile()
{
$path = env('UPLOAD_PATH', 'uploads/default');
Storage::put($path . '/file.txt', 'content');
}
Inside config/filesystems.php
upload_path => env('UPLOADED_PATH', 'uploads/default');
Inside controller
public function uploadFile()
{
$path = config('filesystems.upload_path');
Storage::put($path . '/file.txt', 'content');
}
public function store(Request $request)
{
User::create($request->all());
}
Inside User
model
protected $fillable = ['name', 'email', 'password'];
Inside the controller
public function store(Request $request)
{
$data = $request->only(['name', 'email', 'password']);
$data['password'] = bcrypt(data['password']);
User::create($data);
}
public function index()
{
$users = User::all();
return response()->json($users);
}
public function index()
{
$users = User::paginate(10);
return response()->json($users);
}
public function isNormal(): bool
{
return $article->type === 'normal';
}
return back()->with('message', 'Your article has been added!');
public function isNormal()
{
return $article->type === Article::TYPE_NORMAL;
}
return back()->with('message', __('app.article_added'));
if ($user->type === 'admin') {
// Perform action
}
class User
{
public const TYPE_ADMIN = 'admin';
public const TYPE_CUSTOMER = 'customer';
}
Usage
if ($user->type === User::TYPE_ADMIN) {
// Perform action
}
Route::get('/api/resource', [ApiController::class, 'index']);
Route::middleware('throttle:60,1')->get('/api/resource', [ApiController::class, 'index']);
$input = $request->all();
$input = $request->only(['name', 'email', 'password']);
function calculateAge($birthdate)
{
return \Carbon\Carbon::parse($birthdate)->age;
}
Create a dedicated helper file:
if (!function_exists('calculateAge')) {
function calculateAge($birthdate)
{
return \Carbon\Carbon::parse($birthdate)->age;
}
}
Register the helper in composer.json
:
"autoload": {
"files": [
"app/helpers.php"
]
}
foreach ($users as $user) {
$profile = $user->profile; // Triggers N+1 query issue
}
$users = User::with('profile')->get();
foreach ($users as $user) {
$profile = $user->profile;
}
public function testUserCanLogin()
{
$response = $this->post('/login', ['email' => '[email protected]', 'password' => 'password']);
$response->assertStatus(200);
}
public function testUserCanLogin()
{
$response = $this->post('/login', ['email' => '[email protected]', 'password' => 'password']);
$response->assertStatus(200)
->assertJsonStructure(['token']);
}
$userRepo = new EloquentUserRepository();
Bind the repository in a service provider
$this->app->bind(UserRepository::class, EloquentUserRepository::class);
Usage:
$userRepo = app(UserRepository::class);
class UserController extends Controller
{
public function index()
{
$users = User::all();
return view('users.index', compact('users'));
}
}
interface UserRepository
{
public function getAll();
}
Repository Implementation:
class EloquentUserRepository implements UserRepository
{
public function getAll()
{
return User::all();
}
}
Controller Usage:
class UserController extends Controller
{
private UserRepository $userRepository;
public function __construct(UserRepository $userRepository)
{
$this->userRepository = $userRepository;
}
public function index()
{
$users = $this->userRepository->getAll();
return view('users.index', compact('users'));
}
}
class UserHelper
{
public static function isAdmin($user)
{
return $user->role === 'admin';
}
}
class UserHelper
{
public function isAdmin($user)
{
return $user->role === 'admin';
}
}
Usage:
$userHelper = new UserHelper();
$userHelper->isAdmin($user);
public function sendNotification(Request $request)
{
Mail::to($request->email)->send(new NotificationMail());
}
NotificationJob::dispatch($request->email);
Job Implementation:
class NotificationJob implements ShouldQueue
{
public function __construct(public string $email) {}
public function handle()
{
Mail::to($this->email)->send(new NotificationMail());
}
}
Laravel has some built in functionality and community packages can help instead of using 3rd party packages and tools.
Task | Standard Tools | 3rd Party Tools |
---|---|---|
Authorization | Policies | Entrust, Sentinel and other packages |
Compiling Assests | Laravel Mix, Vite | Grunt, Gulp, and other packages |
Development Environment | Laravel Sail, Homestead | Docker |
Deployment | Laravel Forge | Deployer and other solutions |
Unit Testing | PHPUnit | Pest |
Browser Testing | Laravel Dusk | Codeception |
DB | Eloquent | SQL, Doctrine |
Templates | Blade | Twig |
Working With Data | Laravel Collections | Arrays |
Form Validation | Request classes | Validation in controller |
Authentication | Built In | 3rd party packages, your own solution |
API authentication | Laravel Passport, Laravel Sanctum | 3rd party JWT and OAuth packages |
Creating an API | Built in | Dingo API or similar |
Working with DB structure | Migrations | Working directly with the DB |
Localisition | Built in | 3rd party packages |
Realtime user interfaces | Laravel Echo, Pusher | 3rd party packages and working with WebSockets directly |
Generating testing data | Seeder classes, Model Factories, Faker | Creating testing data manually |
Task scheduling | Laravel Task Scheduler | Scripts and 3rd party packages |
DB | MySQL, PostgreSQL, SQLite, SQL Server | MongoDB |
To follow PSR standards And, follow naming conventions accepted by the Laravel community:
What | How | Good | Bad |
---|---|---|---|
Controller | Singular | ArticaleController |
ArticalesController |
Route | Plural | articles/1 |
article/1 |
Route Name | snake_case with dot notation | users.show_active |
users.show-active , show-active-users |
Model | Singular | User |
Users |
hasOne or belongsTo relationship | Singular | articleComment |
articleComments , article_comments |
All other relationships | Plural | articleComments |
articleComment , article_comments |
Table | Plural | article_comments |
article_comment , articleComments |
Pivot Table | Singular model names in alphabetical order | article_user |
users_article , articles_users |
Table Column | snake_case without model name | meta_title |
MetaTitle , article_meta_title |
Model Proprty | snake_case | $model->created_at |
$model->createdAt |
Foreign Key | Singular model name with _id suffix | article_id |
ArticleId , id_article , article_id |
Primary Key | - | id |
custom_id |
Migration | - | 2017_01_01_000000_create_articles_table |
2017_01_01_000000_articles |
Method | camelCase | getAll |
get_all |
Method in resource controller | Table | store |
saveArticle |
Method in test class | camelCase | testGuestCannotSeeArticle |
test_guest_cannot_see_article |
Variable | camelCase | $articlesWithAuthor |
$articles_with_author |
Collection | Descriptive, Plural | $activeUsers = User::active()->get() |
$active , $data |
Object | Descriptive, Singular | $activeUser = User::active()->first() |
$users , $obj |
Config and language files index | snake_case | articles_enabled |
ArticlesEnabled , articles-enabled |
View | kabab-case | show-filtered.blade.php |
showFiltered.blade.php , show_filtered.blade.php |
Config | snake_case | google_calendar.php |
googleCalendar.php , google-calendar.php |
Contract (Interface) | Adjective or noun | AuthenticationInterface |
Authenticatable , IAuthentication |
Trait | Adjective | Notifiable |
NotificationTrait |
Trait (PSR) | Adjective | NotifiableTrait |
Notification |
Enum | Singular | UserType |
UserTypes , UserTypeEnum |
Form Request | Singular | UpdateUserRequest |
UpdateUserFormRequest , UserFormRequest , UserRequest |
Seeder | Singular | UserSeeder |
UsersSeeder |
Language File Names | Lower case, snake_case | user_management.php , order_status.php |
UserManagement.php , OrderStatus.php |
Language Files | Lower case, snake_case | 'login_failed' , 'user' |
'LoginFailed' , 'User' |
- What is Laravel?
- Laravel is a PHP framework based on the MVC (Model-View-Controller) architecture, designed to make web development easier and faster by providing built-in features like routing, authentication, session management, and more.
- What is Composer in Laravel?
- Composer is a dependancy manager for PHP. It helps manage the libraries and packages required for a Laravel project.
- What are the benefits of using Laravel?
- Built-in tools for common tasks like routing, sessiong handling, and authentication.
- Elegant syntax and expressive ORM (Eloquent).
- Scalability and maintainability.
- Robust security features.
- What are service providers in Laravel?
- Service providers are the central place to configure and bootstrap your application. Laravel's core services are all bootstrapped through service providers.
- What is the Artisan CLI tool?
- Artisan is Laravel's command-line interface that provides various commands to assist developers, such as creating controllers, migrations, and more
- Explain Eloquent ORM in Laravel.
- Eloquent is Laravel's built-in ORM, providing an easy-to-use Active Record implementation. It allows developers to interact with the database by defining models and relationships instead of writing raw SQL queries.
- What are middleware in Laravel?
- Middleware is a way to filter HTTP requests entering your application. Examples include authentication and logging.
- What are migrations in Laravel?
- Migrations are version control for your database. They allow you to modify the database schema programmatically and share the schema across teams.
- How does routing work in Laravel?
- Routes in Laravel are defined in
routes/web.php
for web routes androutes/api.php
for API routes. A typical route is defined using:Route::get('/path', [Controller::class, 'method']);
- Routes in Laravel are defined in
- How do you handle validation in Laravel?
- Validation can be handled using the
validate
method in a controller or by creating a Form Request class.
- Validation can be handled using the
- What are queues in Laravel?
- Queues allow you to defer the processing of time-consuming tasks, such as sending emails, or processing large files.
- What is the differences between
require
anduse
in Laravel?require
includes files in PHP, whereasuse
is used to include namespaces or traits.
- Explain service container in Laravel.
- The service container is a powerful tool for managing class dependencies and performing dependency injection.
- What is a Repository pattern in Laravel?
- The Repository pattern separates the logic that retrieves data from the database from the business logic. It improves code readability and testability.
- What is Laravel Event Broadcasting?
- Broadcasting in Laravel allows you to share events between the server-side and client-side applications, enabling real-time features like notifications.
- What is the difference between
hasOne
andbelongsTo
relationships in Laravel?hasOne
defines a one-to-one relationship where the parent model owns the related model.belongsTo
defines the inverse relationship where the related model is owned by the parent model.
- What is a policy in Laravel?
- Policies are classes that organize authorization logic for a specific model.
- How do you optimize a Laravel application?
- Use caching for routes, views, and queries.
- Optimize the database with proper indexing.
- Use eager loading to avoid N+1 query problems.
- Enable query caching.
- How does Laravel handle error and exception handling?
- Laravel uses the
App\Exceptions\Handler
class to handle all exceptions. You can log errors, render specific views, or redirect users.
- Laravel uses the
- What is the difference between
@include
,@yield
, and@section
in Blade?@include
includes a partial view.@yield
defines a placeholder for a section in a layout.@section
defines content for a section in the layout.
- How can you implement custom helper functions in Laravel?
- Create a helper file, define functions, and load it via Composer's autoload configuration in
composer.json
.
- Create a helper file, define functions, and load it via Composer's autoload configuration in
- What are jobs and workers in Laravel?
- Jobs represent tasks to be processed, and workers are the processes that execute those tasks.
- What is Laravel Telescope?
- Telescope is a debugging assistant for Laravel that provides insights into requests, jobs, database queries, and more.
- How can you implement caching in Laravel?
- You can use caching drivers like file, database, Redis, or Memcached. Example:
Cache::put('key', 'value', $seconds); Cache::get('key');
- You can use caching drivers like file, database, Redis, or Memcached. Example:
- What are facades in Laravel? How do they work?
- Facades provide a static interface to classes in the service container. They act as a proxy to underlying classes and allow calling methods without needing to instantiate the class. Example:
Cache::get('key')
.
- Facades provide a static interface to classes in the service container. They act as a proxy to underlying classes and allow calling methods without needing to instantiate the class. Example:
- What is the difference between
public
,protected
, andprivate
in a Laravel context?public
: Methods or properties accessible from anywhere.protected
: Accessible only within the class and its subclasses.private
: Accessible only within the class where it's declared.
- What is the use of the
boot
method in Eloquent models?- The
boot
method is used to observe or hook into Eloquent model events (e.g., creating, updating, deleting) and to set global scopes.
- The
- What are traits in Laravel?
- Traits are used to include reusable methods in multiple classes. Example: Using
SoftDeletes
to enable soft deletion functionality in models.
- Traits are used to include reusable methods in multiple classes. Example: Using
- What is the difference between
Auth::attempt()
andAuth::login()
?Auth::attempt()
validates user credentials and logs in the user if valid.Auth::login()
directly logs in a user without validating credentials.
- How does the Laravel Gate work?
- Gates provide a way to define and authorize user actions at a higher level, like determining if a user can update a post:
Gate::define('update-post', function ($user, $post) { return $user->id === $post->user_id; });
- Gates provide a way to define and authorize user actions at a higher level, like determining if a user can update a post:
- What is Sanctum in Laravel? How is it different from Passport?
- Sanctum is a lightweight authentication system for API tokens and SPA authentication. Passport is for full OAuth2 authentication.
- What is a Laravel package? How do you create one?
- Packages extend Laravel's functionality. To create one:
- Set up a package directory structure.
- Define service providers.
- Publish assets or configurations as needed.
- Packages extend Laravel's functionality. To create one:
- What is the
event:listen
andevent:dispatch
mechanism?event:listen
registers an event listener, whileevent:dispatch
triggers the event. Example:Event::listen(UserRegistered::class, SendWelcomeEmail::class); event(new UserRegistered($user));
- What is Laravel Horizon?
- Horizon is a dashboard tool for monitoring and managing Laravel queues powered by Redis.
- Explain the
$fillable
and$guarded
properties in Laravel models.$fillable
: Specifies fields allowed for mass assignment.$guarded
: Specifies fields that are not mass assignable.
- What is the purpose of
broadcastOn()
in Laravel events?- It defines the channels the event should be broadcast on.
- What is the difference between
session
andcache
in Laravel?session
stores user specific data for the duration of the user's session (e.g. user login info). It typically uses storage like files, database, or cookiescache
temporarily stores application data to optimise performance. It uses faster storage systems like Redis or Memchached.
- What is the use of the
dd()
function in Laravel?dd()
stands for "Dump and Die". It is a debugging function used to dump variable contents and stop script execution.
- How does Laravel handle APIs?
- Laravel provides tools for building RESTful APIs:
- Use
routes/api.php
for API routes. - Return
JSON
responses:return response()->json(['data' => $data]);
- Use
Resource
classes for API responses:php artisan make:resource UserResource
- Example in controller:
return new UserResource(User::find(1));
- Use
- Laravel provides tools for building RESTful APIs: