Найти в Дзене

Лучшие практики. Laravel

Ниже краткая выборка из статей указанных снизу, с другими примерами. Контроллеры должны только принять запрос и отправить его исполнителю Плохой пример: class UserController extends Controller
{
public function register(Request $request)
{
$validated = $request->validate([
'name' => 'required|string',
'email' => 'required|email|unique:users',
'password' => 'required|min:8',
]);
// Создание пользователя
$user = new User();
$user->name = $validated['name'];
$user->email = $validated['email'];
$user->password = bcrypt($validated['password']);
$user->save();
// Создание профиля
$profile = new Profile();
$profile->user_id = $user->id;
$profile->save();
// Отправка письма
Mail::to($user->email)->send(new WelcomeEmail($user));
return redirect('/dashboard');
}
} Хороший пример: class UserController extends Controller
{
Оглавление

Ниже краткая выборка из статей указанных снизу, с другими примерами.

1. Толстые модели и тонкие контроллеры

Контроллеры должны только принять запрос и отправить его исполнителю

Плохой пример:

class UserController extends Controller
{
public function register(Request $request)
{
$validated = $request->validate([
'name' => 'required|string',
'email' => 'required|email|unique:users',
'password' => 'required|min:8',
]);

// Создание пользователя
$user = new User();
$user->name = $validated['name'];
$user->email = $validated['email'];
$user->password = bcrypt($validated['password']);
$user->save();

// Создание профиля
$profile = new Profile();
$profile->user_id = $user->id;
$profile->save();

// Отправка письма
Mail::to($user->email)->send(new WelcomeEmail($user));

return redirect('/dashboard');
}
}

Хороший пример:

class UserController extends Controller
{
// валидацию оставляем реквесту
public function register(UserRequest $request)
{
// прочую логику выносим в сервис
(new UserService)->register($request->validated());

return redirect('/dashboard');
}
}

2. Методы должны делать что-то одно

Плохой пример:

public function store(Request $request)
{
// 1. Валидация
$validated = $request->validate([
'product_id' => 'required|exists:products,id',
'quantity' => 'required|integer|min:1',
'user_id' => 'required|exists:users,id',
]);

// 2. Создание заказа по условиям
$order = new Order();
$order->user_id = $validated['user_id'];
$order->product_id = $validated['product_id'];
$order->quantity = $validated['quantity'];

if ($validated['quantity'] > 10) {
$order->discount = 10;
} else {
$order->discount = 0;
}

$order->save();

// 3. Логирование
Log::
info("New order created: #{$order->id}");

// 4. Отправка SMS
$smsService = new SomeSmsService();
$smsService->send($order->user->phone, "Your order #{$order->id} has been placed");

// 5. Возврат ответа
return response()->json($order, 201);
}

Хороший пример:

public function __construct(
private OrderService $orderService,
private OrderLogger $orderLogger,
private SmsNotification $smsNotification
) {}

public function store(OrderRequest $request)
{
$order = $this->orderService->createOrder($request->validated());

$this->orderLogger->log($order);

$this->smsNotification->sendOrderCreated($order);

return response()->json($order, 201);
}

3. Избегайте бизнес-логику в роутах

Роуты должны только направлять запросы, а не содержать логику.

Плохой пример:

Route::get('/activate/{user}', function (User $user) {
$user->activate();
return redirect('/dashboard');
});

Хороший пример:

Route::get('/activate/{user}', [UserController::class, 'activate']);

// UserController
public function activate(User $user) {
$user->activate();
return redirect('/dashboard');
}

4. Используйте чанки данных для повышения производительности

Плохой пример:

public function processOrders()
{
// Плохо: загружаем ВСЕ записи сразу в память
$orders = Order::all(); // Если записей 100 000 - это убьёт память

foreach ($orders as $order) {
// Какая-то бизнес-логика
}

return response()->json(['message' => 'Orders processed']);
}

Хороший пример:

public function processOrders()
{
// Хорошо: обрабатываем по 100 записей за раз
Order::where('processed', false)->chunk(100, function ($orders) {
foreach ($orders as $order) {
// Какая-то бизнес-логика
}
});

return response()->json(['message' => 'Orders processed']);
}

5. Используйте константы вместо жестко заданных значений

Также можно использовать enums и конфиги

Плохой пример:

if ($type === 'mask') {
// ...
}

Хороший пример:

if ($type === $this::MASK) {
// ...
}

6. Всегда используйте перевод строк

Обернуть строку в нужный оператор не долго и, даже если мультиязычности в проекте нету, никто не знает появится ли она в дальнейшем

Плохой пример:

return 'Заказ успешно создан'

Хороший пример:

return __('Заказ успешно создан')

7. Используйте внедрение зависимостей

Плохой пример:

class PaymentController extends Controller
{
public function processPayment()
{
// Плохо: создание зависимостей напрямую через new
$gateway = new StripeGateway();
$logger = new DatabaseLogger();
$notifier = new SmsNotifier();

// Какая-то бизнес-логика
$payment = $gateway->charge(1000, 'USD');

$logger->log('Payment processed: ' . $payment->id);
$notifier->send('Payment successful!');

return response()->json($payment);
}
}

Хороший пример:

class PaymentController extends Controller
{
protected $gateway;
protected $logger;
protected $notifier;

// Хорошо: зависимости внедряются через конструктор
public function __construct(
PaymentGateway $gateway,
Logger $logger,
Notifier $notifier
) {
$this->gateway = $gateway;
$this->logger = $logger;
$this->notifier = $notifier;
}

public function processPayment()
{
// Бизнес-логика использует внедренные зависимости
$payment = $this->gateway->charge(1000, 'USD');

$this->logger->log('Payment processed: ' . $payment->id);
$this->notifier->send('Payment successful!');

return response()->json($payment);
}
}

8. Избегайте прямого использования .env в коде

Плохой пример:

public function getToken()
{
return env('SOME_API_TOKEN');
}

Хороший пример:

public function getToken()
{
return config('some_service.api_token');
}

9. Выносите валидацию в реквесты

Можно взять из примера выше

Плохой пример:

public function store(Request $request)
{
$validated = $request->validate([
'product_id' => 'required|exists:products,id',
'quantity' => 'required|integer|min:1',
'user_id' => 'required|exists:users,id',
]);

// ...
}

Хороший пример:

public function store(StoreRequest $request)
{
$validated = $
request->validated();
// ...
}

10.Предпочитайте читаемые имена переменных и методов комментариям

Плохой пример:

// Determine if there are any joins
if (count((array) $builder->getQuery()->joins) > 0)

Хороший пример:

if ($this->hasJoins())

References:

laravel-best-practices/russian.md at master · alexeymezenin/laravel-best-practices
Laravel Best Practices