Appearance
Laravel conventions
Introduction
These conventions aim to standardize our Laravel development practices, focusing on:
- Reducing ambiguity
- Enhancing consistency
- Optimizing tool integration (IDEs, static analyzers, etc.)
Strategy
- Consistency is Key: When Laravel offers multiple approaches, we define a single, consistent method in these conventions.
- Performance and Scalability: Adopt patterns that enhance application performance and maintainability as it scales.
- Security-First Mindset: Incorporate security best practices throughout the development process.
- Leverage Laravel's Intentions: Maximize the use of native Laravel features and official packages. Deviate only with clear justification.
This guide assumes familiarity with the latest Laravel version and modern PHP development practices. It focuses on our specific conventions and rationales rather than explaining basic concepts.
Project Structure
For large projects (> 100 Models), use modules to separate the codebase into smaller parts. Use the standard Laravel structure for each module:
text
Modules/
...
Course/
Actions/
Event/
Exceptions/
Console
Commands/
Http/
Controllers/
StoreCourseEnrollmentController.php
StoreCourseEnrollmentRequest.php
Middleware/
Resources/
Jobs/
Listeners/
Models/
Policies/
Rules/
View/
CourseServiceProvider.php
...
...other modulesExceptions:
- Do not create a separate directory for Request classes: they are not reusable and often have the same reason for change as the Controller, so they should be in the same directory (Controllers).
- Do not create a separate directory for Providers classes: move them to the root of the module directory. ServiceProvide provide usually does job on module level and Module root is the best place for it. every module usually has a single provider and this it does not clutter the directory.
Modules are relatively independent parts of the application that can be developed and tested separately. Of course, modules should communicate with each other, but they should not depend on each other. Such communication possible using:
- Dependency injection using interfaces (it's ok to use interfaces from other modules)
- Events and Listeners
DI vs. Facades vs. Facade aliases vs. helper functions
DI and Facades SHOULD be used in PHP code, helpers SHOULD be used in Blade views.
The biggest advantage of using dependency injection is the explicit and clear contract of the class. Public methods indicate what tasks this class can perform. Constructor parameters specify what the class needs for these tasks. In large, long-lasting projects, this is essential. Classes can be easily tested and used in any conditions; you need to provide them with the necessary dependencies (yes, we know, Laravel Facades are easy to test too).
On the other hand, Laravel doesn't provide alternatives to some helpers and Facades. Also, it's hard for me to imagine, for example, HTTP controllers outside of a Laravel application. Therefore, it's quite appropriate to use helper functions and Laravel Facades in this context.
So, the general rule is to prefer DI, then Facade, then helpers.
Exceptions for helpers (ok to use):
config()- routing:
route()url()
- response (scope: in HTTP layer only [controllers and middlewares]):
abort()response()redirect()view()
- path helpers (
\Illuminate\Contracts\Foundation\Applicationcontact doesn't have these methods):app_path()base_path()database_path()lang_path()public_path()resource_path()storage_path()
- queue:
dispatch()(it's not the same asBus::dispatch:dispatch()respects toUniqueLock, the Facade doesn't)dispatch_sync()(for consistency withdispatch())
- time:
now()today()
- localization:
__()(preferred)trans()trans_choice()
Facade root aliases
Don’t use Facade root aliases (comment out Facade::defaultAliases()->merge([...])): it’s extra magic that’s easy to avoid. Exceptions:
\Vitealias for\Illuminate\Support\Facades\Vite(why: there are no helper alternatives forVite::asset()that is commonly used in Blade views)
Models
See separate file See separate file See separate file See separate file
Factories
See separate file
Migrations
See separate file
Seeders
See separate file
Artisan commands
See separate file
Controllers
See separate file
Requests
See separate file
Responses
See separate file
Routing and API Design
See separate file
Authorization
See separate file
Validation
See separate file
Exceptions
See separate file
Jobs
See separate file
Events
See separate file
Configs
See separate file
Tests
See separate file
Materials
- Matthias Noback: Recipes for Decoupling
- Adel Faizrakhmanov: Architecture of Complex Web Applications
- Spatie guidelines
🦄