Laravel — мощный и удобный фреймворк, но если лепить всё в контроллеры и модели, то через пару месяцев проект превращается в кашу. Чтобы не захлебнуться в собственном коде — нужна архитектура.
Рассказываю, как я организую большие Laravel-проекты, чтобы и самому не страдать, и другим было понятно.
📁 1. Разделяй слои: контроллеры — не мусорка
Контроллер не должен содержать бизнес-логику. Его задача — принять запрос, передать данные дальше и вернуть ответ.
Пример плохо:
public function store(Request $request)
{
$user = User::create([
'name' => $request->name,
'email' => $request->email,
]);
Mail::to($user->email)->send(new WelcomeMail($user));
return redirect()->back();
}
Пример лучше:
public function store(StoreUserRequest $request)
{
$this->userService->createUser($request->validated());
return back();
}
⚙️ 2. Используй слои: Service, Action, DTO
- Service — общая бизнес-логика
- Action — конкретное действие (например, CreateUserAction)
- DTO (Data Transfer Object) — объект для передачи данных
Пример DTO:
class CreateUserDTO
{
public function __construct(
public string $name,
public string $email,
) {}
}
И ты передаёшь его вот так:
$dto = new CreateUserDTO(
name: $request->name,
email: $request->email,
);
$this->createUserAction->handle($dto);
📚 3. Храни бизнес-логику вне моделей
Eloquent-модели хороши, но не надо превращать их в мусорные ведра с кучей методов.
Плохо:
class User extends Model
{
public function sendWelcomeMail()
{
Mail::to($this->email)->send(new WelcomeMail($this));
}
}
Лучше:
Вынеси это в отдельный MailService или Action.
🔁 4. Валидация — через Form Request
Не пиши в контроллере if ($request->has(...)). Используй php artisan make:request — и вся валидация будет в одном месте.
class StorePostRequest extends FormRequest
{
public function rules(): array
{
return [
'title' => 'required|string|max:255',
'body' => 'required|string',
];
}
}
🧪 5. Думай о тестах с самого начала
Когда логика разбита по слоям (Actions, Services), писать тесты — одно удовольствие.
it('creates user', function () {
$dto = new CreateUserDTO('Test', 'test@mail.com');
$user = app(CreateUserAction::class)->handle($dto);
expect($user)->toBeInstanceOf(User::class);
});
📦 6. Структура проекта
Вот пример структуры без перегруза:
app/
├── Actions/
├── DTOs/
├── Http/
│ ├── Controllers/
│ └── Requests/
├── Models/
├── Services/
├── ViewModels/
Такой порядок легко читать, и по названию файлов понятно, что где лежит.
🔚 Вывод
Чистая архитектура — это не модная тема для конференций. Это здравый смысл.
Пиши так, чтобы самому не было больно поддерживать проект через полгода.
Делай код читаемым, логичным и разбитым на понятные куски. Laravel это позволяет — бери и делай.