Architecture
Model
Models are classes that represent database tables. They allow you to interact with the corresponding data using object-oriented syntax.
In other words, models provide an easy way to query, insert, update, and delete data in a database table. Read more
Create command: php artisan make:model Product
1class Product extends Model2{3 use HasFactory;4}
Naming
Singular without "Model" suffix (User
, Product
, Category
...)
Best practices
- Follow the defined structure:
- Attributes -
$fillable
,$casts
… - Lifecycle methods -
boot()
,booted()
- Relationships - belongs, has, morphs…
- Accessors & mutators
- Other methods
- Models should contain only Laravel native things (relations, scopes…) and database-related code.
- Your business logic should be written into
Support
orAction
classes.
- Use mass assignment where possible.
- The code for creating/updating the model is shorter and cleaner.
- Prefer
$fillable
over$guarded
.
- Generally safer method => reduces the risk of data issues.
- Greater control over attributes.
- Ability to easily find database column names by only opening the model.
Controller
Controllers handle requests and responses. In fact, they are intermediaries between the database, views, and business logic. Read more
Create command: php artisan make:controller UserController
1class UserController extends Controller2{3 //4}
Naming
Singular with "Controller" suffix (UserController
, ProductController
, CategoryController
...)
Types
-
resource - contains methods for each
CRUD
operation also with methods that present HTML templates such ascreate
andedit
-
api - contains also a method for each
CRUD
operation, but does not provide HTML templates methods - invokable - controllers for single actions that do not match resources
Best practices
- Keep controller methods thin.
- They should not contain huge business logic.
- They are mainly responsible for one thing - returning a response.
- Use resource controllers for
CRUD
operations.
- Resource defines
CRUD
methods by following naming conventions.
Namespacing
When you have multiple types of controllers (for API
, for Admin...), you should group them by the following structure:
1Admin/UserController.php2Api/Admin/UserController.php3Api/UserController.php4UserController.php
Request
Requests are objects that encapsulate the input data from an HTTP request.
They provide a convenient way to validate and process user input before using it in your application. Read more
Create command: php artisan make:request StoreUserRequest
1class StoreUserRequest extends FormRequest 2{ 3 /** 4 * Determine if the user is authorized to make this request. 5 */ 6 public function authorize() 7 { 8 return true; 9 }10 11 /**12 * Get the validation rules that apply to the request.13 */14 public function rules()15 {16 return [17 //18 ];19 }20}
Naming
Method name with singular model name and with "Request" suffix (StoreUserRequest
, StoreProductRequest
, UpdateCategoryRequest
...)
Configuration
Configurations are always stored in the config
directory.
Warning: You should never access the
env()
method directly in application. You should use it only in configuration files and access it byconfig()
method.
Best practices
- Access config values only via
config()
method. - Store custom application settings in seprated config file.
- e.g.
project.php
- API keys of 3rd party services should be stored in
services.php
.
Action
Actions are classes responsible for only one single task. Code is cleaner and simpler.
Create command: php artisan make:action VerifyUserAction
1class VerifyUserAction 2{ 3 /** 4 * Run the action. 5 */ 6 public function run(): void 7 { 8 // 9 }10}
Tip: This command is not part of Laravel framework, install our package
rockero-cz/laravel-starter-kit
to get a bit of magics.
Naming
Action purpose name with "Action" suffix (VerifyUserAction
, CreateProductAction
, ReorderCategoryAction
...)
Best practices
- Each action should contain only one public method.
- Use some self-explanatory name such as
run()
orexecute()
.
- Action helper methods should be private or protected.
- Multiple helper methods may be converted to
Support
classes.
Support
Support classes are a way to group related functions and logic together in a single class. They allow for easy reuse of code and help to keep application code organized.
They are typically used to provide functionality that is not specific to a single model or controller, but rather is used across multiple parts of an application.
It is simpler alternative than using services.
Create command: php artisan make:class Support/Cart
1class Cart2{3 //4}
Tip: This command is not part of Laravel framework, install our package
rockero-cz/laravel-starter-kit
to get a bit of magics.
Naming
Support purpose name without "Support" suffix (Cart
, OpeningHours
, Table
...)
Routing
Route Types
- web - Routes that handle web-based HTTP requests and responses…
- api - Routes that handle API requests and responses…
- channels - Routes that handle real-time broadcasting to channels using websockets…
- console - Routes for custom commands that can be executed via Artisan CLI…
Best practices
- URLs should be in plural.
- Each route should have name.
- Routes should be grouped by entities.
1Route::middleware('auth')->group(function () {2 Route::name('users.')->group(function () {3 Route::get('/', UserIndex::class)->name('index');4 Route::get('/{user}', UserShow::class)->name('show');5 });6});
Middleware
Middleware is a way to filter and modify incoming HTTP requests in your application, allowing you to perform various tasks such as authentication, authorization, and session management.
You should create middleware in cases when you need to do some specific logic for a specific group of routes. Read more
Create command: php artisan make:middleware HandleLocale
1class HandleLocale 2{ 3 /** 4 * Handle an incoming request. 5 */ 6 public function handle(Request $request, Closure $next): Response 7 { 8 return $next($request); 9 }10}
Usage example
1Route::prefix('/admin')->name('admin.')->middleware(HandleLocale::class)->group(function () {2 Route::resource('users', UserController::class)->name('users');3 Route::resource('orders', OrderController::class)->name('orders');4});
Observer
Observers are used to listen for specific events that occurred by models, such as created
, updated
, or deleted
and more...
By using observers, you can keep your model classes focused on their primary responsibilities and avoid cluttering them with additional logic. Read more
Warning: Eloquent mass update queries do not perform the event and the observer is not triggered. It is caused because models are not actually loaded when doing a mass update but only SQL query is.
Create command: php artisan make:observer UserObserver --model=User
1class UserObserver 2{ 3 /** 4 * Handle the User "created" event. 5 */ 6 public function created(User $user): void 7 { 8 // 9 }10}
Naming
Singular model name with "Observer" suffix (UserObserver
, ProductObserver
, CategoryObserver
...)
Usage example
1// Recalculate invoice when the invoice item is saved. 2public function saved(InvoiceItem $invoiceItem): void 3{ 4 $invoiceItem->invoice()->recalculate(); 5} 6 7// Set default state when the order is created. 8public function creating(Order $order): void 9{10 $order->state = OrderState::NEW;11}12 13// Delete relations before the model is deleted.14public function deleting(Order $order): void15{16 $order->products()->delete();17}
Event
Events are a way to trigger and handle actions that occur during the execution of your application. They are used in combination with listeners.
When an event is dispatched, Laravel will notify all registered listeners for that event, giving them a chance to perform any necessary actions. Read more
We primarily use actions instead of events because they are more simple and understandable. However, we use still events for some notifications or in combination with websockets.
Create command: php artisan make:event OrderCreated
1class OrderCreated 2{ 3 use Dispatchable, InteractsWithSockets, SerializesModels; 4 5 /** 6 * Create a new event instance. 7 */ 8 public function __construct() 9 {10 //11 }12 13 /**14 * Get the channels the event should broadcast on.15 */16 public function broadcastOn(): Channel|array17 {18 return new PrivateChannel('channel-name');19 }20}
Dispatching events
1OrderCreated::dispatch();2 3// or4 5event(new OrderCreated());
Listeners
Create command: php artisan make:listener SendOrderCreatedNotification --event=OrderCreated
1class SendOrderCreatedNotification 2{ 3 /** 4 * Create the event listener. 5 */ 6 public function __construct() 7 { 8 // 9 }10 11 /**12 * Handle the event.13 */14 public function handle(OrderCreated $event): void15 {16 //17 }18}
Command
Commands are a powerful tool for automating some tasks in your application. Laravel also provides a set of built-in commands that you can use out of the box.
With commands, you can easily perform repetitive actions like running tests or executing database migrations, with minimal effort. Read more
Create command: php artisan make:command FetchUsers
1class FetchUsers extends Command 2{ 3 protected $signature = 'command:name'; 4 protected $description = 'Command description'; 5 6 /** 7 * Execute the console command. 8 */ 9 public function handle(): int10 {11 return Command::SUCCESS;12 }13}
Scheduling commands
You can easily run commands at specified intervals or times using Scheduler.
1// app/Console/Kernel.php2protected function schedule(Schedule $schedule)3{4 $schedule->command('telescope:prune')->daily();5}