← Назад к вопросам

Что такое контроллер в MVC?

1.0 Junior🔥 221 комментариев
#Архитектура и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI21 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

# Контроллер в MVC паттерне

Контроллер - это один из трёх ключевых компонентов MVC архитектуры. Это промежуточный слой между пользовательским запросом и бизнес-логикой.

Определение

Контроллер - это класс/компонент, который:

  1. Получает HTTP запрос
  2. Обрабатывает/валидирует данные
  3. Взаимодействует с моделями (бизнес-логикой)
  4. Возвращает ответ (JSON, HTML, redirect и т.д.)

MVC архитектура

HTTP Запрос
    ↓
[CONTROLLER] ← здесь мы
    ↓
[MODEL] - бизнес логика
    ↓
[VIEW] - шаблон/JSON
    ↓
HTTP Ответ

Пример контроллера в Laravel

// app/Http/Controllers/UserController.php
class UserController extends Controller {
    // Зависимости внедрены
    public function __construct(
        private UserService $userService,
        private UserRepository $repository
    ) {}
    
    // GET /users - Получить список
    public function index() {
        $users = $this->repository->paginate(15);
        return response()->json($users);
    }
    
    // GET /users/{id} - Получить по ID
    public function show(int $id) {
        $user = $this->repository->findById($id);
        
        if (!$user) {
            return response()->json(['error' => 'Not found'], 404);
        }
        
        return response()->json($user);
    }
    
    // POST /users - Создать
    public function store(CreateUserRequest $request) {
        // Request автоматически валидирует данные
        try {
            $user = $this->userService->register(
                $request->validated()
            );
            return response()->json($user, 201);
        } catch (Exception $e) {
            return response()->json(['error' => $e->getMessage()], 422);
        }
    }
    
    // PUT /users/{id} - Обновить
    public function update(int $id, UpdateUserRequest $request) {
        $user = $this->repository->findById($id);
        
        if (!$user) {
            return response()->json(['error' => 'Not found'], 404);
        }
        
        $this->userService->updateUser($user, $request->validated());
        
        return response()->json($user);
    }
    
    // DELETE /users/{id} - Удалить
    public function destroy(int $id) {
        $user = $this->repository->findById($id);
        
        if (!$user) {
            return response()->json(['error' => 'Not found'], 404);
        }
        
        $this->userService->deleteUser($user);
        
        return response()->noContent();  // 204
    }
}

Обязанности контроллера

1. Получение и валидация входных данных

public function store(CreateUserRequest $request) {
    // Автоматическая валидация через Request класс
    $validated = $request->validated();
    // Если невалидно, Laravel автоматически вернет 422
}

// CreateUserRequest
class CreateUserRequest extends FormRequest {
    public function rules(): array {
        return [
            'email' => 'required|email|unique:users',
            'name' => 'required|string|max:255',
            'password' => 'required|min:8|confirmed',
        ];
    }
}

2. Преобразование и подготовка данных

public function uploadAvatar(UploadAvatarRequest $request) {
    $file = $request->file('avatar');
    
    // Преобразуем файл
    $path = $file->store('avatars', 'public');
    $url = Storage::url($path);
    
    // Обновляем профиль
    $this->userService->updateAvatar(auth()->user(), $url);
    
    return response()->json(['avatar_url' => $url]);
}

3. Вызов бизнес-логики (Service)

public function placeOrder(PlaceOrderRequest $request) {
    // Контроллер НЕ содержит логику, только вызывает Service
    $order = $this->orderService->placeOrder(
        user: auth()->user(),
        items: $request->get('items'),
        shippingAddress: $request->get('address')
    );
    
    return response()->json($order, 201);
}

4. Обработка ошибок и исключений

public function purchase(PurchaseRequest $request) {
    try {
        $order = $this->orderService->placeOrder($request->validated());
        return response()->json($order, 201);
    } 
    catch (OutOfStockException $e) {
        return response()->json(
            ['error' => 'Some items are out of stock'],
            422
        );
    }
    catch (PaymentFailedException $e) {
        return response()->json(
            ['error' => 'Payment processing failed'],
            422
        );
    }
    catch (Exception $e) {
        Log::error('Order placement failed', ['error' => $e->getMessage()]);
        return response()->json(
            ['error' => 'Server error'],
            500
        );
    }
}

5. Формирование ответа

public function show(int $id) {
    $user = $this->repository->findById($id);
    
    // JSON ответ
    return response()->json($user);
    
    // HTML ответ (если есть views)
    return view('users.show', ['user' => $user]);
    
    // Redirect
    return redirect()->route('users.show', $user);
    
    // Download файл
    return response()->download(storage_path('invoices/123.pdf'));
    
    // Custom статус код
    return response()->json($user, 202);  // 202 Accepted
}

Правильный контроллер (thin controller)

// ✅ ХОРОШО - контроллер тонкий, логика в service
class PaymentController extends Controller {
    public function __construct(
        private PaymentService $paymentService
    ) {}
    
    public function checkout(PaymentRequest $request) {
        // Минимум логики - только получить данные и вызвать service
        $result = $this->paymentService->processPayment(
            amount: $request->get('amount'),
            paymentMethod: $request->get('method'),
            user: auth()->user()
        );
        
        if ($result->isSuccessful()) {
            return response()->json(['success' => true]);
        }
        
        return response()->json(
            ['error' => $result->getErrorMessage()],
            422
        );
    }
}

Неправильный контроллер (fat controller)

// ❌ ПЛОХО - вся логика в контроллере
class PaymentController extends Controller {
    public function checkout(Request $request) {
        // Валидация
        if (!$request->has('amount') || !is_numeric($request->get('amount'))) {
            return response()->json(['error' => 'Invalid amount'], 422);
        }
        
        // Бизнес логика прямо в контроллере!
        $user = auth()->user();
        $amount = $request->get('amount');
        $method = $request->get('method');
        
        // Валидация метода платежа
        if (!in_array($method, ['card', 'paypal', 'apple_pay'])) {
            return response()->json(['error' => 'Invalid method'], 422);
        }
        
        // Обработка платежа
        if ($method === 'card') {
            $curl = curl_init();
            curl_setopt($curl, CURLOPT_URL, 'https://stripe.com/...');
            // ... много кода ...
            $response = curl_exec($curl);
        }
        
        // Сохранение в БД
        $order = new Order();
        $order->user_id = $user->id;
        $order->amount = $amount;
        $order->status = 'completed';
        $order->save();
        
        // Отправка уведомления
        Mail::send(new OrderConfirmation($order));
        
        // ВСЁ В ОДНОМ МЕТОДЕ!
    }
}

REST контроллер (RESTful API)

// Стандартные методы для REST
class ProductController extends Controller {
    // GET /products
    public function index() {
        return $this->productService->list();
    }
    
    // POST /products
    public function store(CreateProductRequest $request) {
        return $this->productService->create($request->validated());
    }
    
    // GET /products/{id}
    public function show(int $id) {
        return $this->productService->findById($id);
    }
    
    // PATCH /products/{id}
    public function update(int $id, UpdateProductRequest $request) {
        return $this->productService->update($id, $request->validated());
    }
    
    // DELETE /products/{id}
    public function destroy(int $id) {
        $this->productService->delete($id);
        return response()->noContent();
    }
}

// routes/api.php
Route::apiResource('products', ProductController::class);
// Автоматически создает маршруты: index, store, show, update, destroy

Контроллер с дополнительными action'ами

class OrderController extends Controller {
    // Стандартные RESTful методы
    public function index() {}
    public function store() {}
    public function show() {}
    public function update() {}
    public function destroy() {}
    
    // Дополнительные действия
    public function cancel(int $orderId) {
        $this->orderService->cancelOrder($orderId);
        return response()->json(['status' => 'cancelled']);
    }
    
    public function refund(int $orderId) {
        $this->orderService->refundOrder($orderId);
        return response()->json(['status' => 'refunded']);
    }
    
    public function getTimeline(int $orderId) {
        return $this->orderService->getTimeline($orderId);
    }
}

// routes/api.php
Route::apiResource('orders', OrderController::class);
Route::post('orders/{orderId}/cancel', [OrderController::class, 'cancel']);
Route::post('orders/{orderId}/refund', [OrderController::class, 'refund']);
Route::get('orders/{orderId}/timeline', [OrderController::class, 'getTimeline']);

Принципы хорошего контроллера

✅ THIN CONTROLLER (тонкий):
   - Валидация входных данных
   - Вызов сервиса
   - Возврат ответа
   
❌ FAT CONTROLLER (толстый):
   - Прямой доступ к БД
   - Вся бизнес-логика
   - SQL запросы
   - Отправка email
   - Внешние API вызовы

✅ DO:
   - Validate input
   - Call services
   - Return response
   - Handle errors
   
❌ DON'T:
   - Write SQL queries
   - Complex business logic
   - Database transactions
   - External API calls
   - Transformation logic

Итог

Контроллер - это входная точка для HTTP запроса. Его роль:

  1. Получить данные из запроса
  2. Валидировать данные
  3. Вызвать бизнес-логику (Service)
  4. Вернуть ответ

Главный принцип: Контроллер должен быть тонким. Вся логика должна быть в Service, Repository и Domain моделях.