Контроллер для модели User в Laravel: полное руководство

Раздел: PHP разработка -> Laravel контроллеры

Контроллер пользователя в Laravel: создание, методы и варианты

Наиболее эффективное решение для работы с пользователями в Laravel - использование Resource Controller с полным набором CRUD-методов. Этот подход соответствует соглашениям фреймворка и легко масштабируется.

Создание контроллера выполняется командой:

php artisan make:controller UserController --resource --model=User

Controller user php (контроллер пользователя в php)

Данная команда генерирует класс UserController с методами index(), create(), store(), show(), edit(), update(), destroy() и автоматически подключает модель User.

Регистрация маршрутов в файле web.php:

Route::resource('users', UserController::class);

Пример реализации метода store():

public function store(Request $request)
{
    $validated = $request->validate([
        'name'     => 'required|string|max:255',
        'email'    => 'required|email|unique:users',
        'password' => 'required|string|min:8',
    ]);

    $user = User::create($validated);
    $user->password = bcrypt($request->password);
    $user->save();

    return redirect()->route('users.index')->with('success', 'Пользователь создан');
}

Описание шагов:

  1. Валидация входных данных - обязательное поле, уникальный email, минимальная длина пароля.
  2. Создание записи в базе через User::create().
  3. Хеширование пароля с помощью bcrypt().
  4. Редирект на список пользователей с flash-сообщением.

Типичная ошибка: забыть хешировать пароль или использовать массовое присвоение без заполнения свойства $fillable в модели. Решение - добавить в модель User массив protected $fillable = ['name','email','password'];

Как организовать валидацию данных при создании пользователя с помощью FormRequest?

Вынос валидации в отдельный класс (Form Request) делает код чище и позволяет переиспользовать правила.

Создание Form Request:

php artisan make:request StoreUserRequest

Класс app/Http/Requests/StoreUserRequest.php:

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreUserRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }

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

Использование в контроллере:

public function store(StoreUserRequest $request)
{
    $validated = $request->validated();
    $validated['password'] = bcrypt($validated['password']);

    $user = User::create($validated);

    return redirect()->route('users.index');
}

Цель: разделение ответственности, автоматическая обработка ошибок валидации (редирект с ошибками).

Возможная проблема: FormRequest не срабатывает, если не указан путь в RouteServiceProvider или присутствуют конфликты с middleware. Решение - проверить регистрацию маршрута и убедиться, что authorize() возвращает true.

Как вынести бизнес-логику создания пользователя в отдельный сервис?

Сервисный слой позволяет избежать «распухания» контроллера и упрощает тестирование.

Создаём класс App\Services\UserService:

<?php

namespace App\Services;

use App\Models\User;
use Illuminate\Support\Facades\Hash;

class UserService
{
    public function create(array $data): User
    {
        $data['password'] = Hash::make($data['password']);
        return User::create($data);
    }

    public function update(User $user, array $data): bool
    {
        if (isset($data['password'])) {
            $data['password'] = Hash::make($data['password']);
        }
        return $user->update($data);
    }

    public function delete(User $user): bool
    {
        return $user->delete();
    }
}

Контроллер с внедрением зависимости:

use App\Services\UserService;

class UserController extends Controller
{
    protected $userService;

    public function __construct(UserService $userService)
    {
        $this->userService = $userService;
    }

    public function store(StoreUserRequest $request)
    {
        $user = $this->userService->create($request->validated());

        return redirect()->route('users.index', $user);
    }
}

Цель: изоляция логики, возможность подмены сервиса при тестировании.

Типичная ошибка: забыть зарегистрировать сервис в контейнере. В Laravel автоматическое разрешение работает для классов без интерфейсов, поэтому обычно регистрация не требуется. Если используется интерфейс, нужно связать в AppServiceProvider.

Как сделать одноразовый контроллер для регистрации пользователя (Invokable)?

Когда контроллер выполняет только одно действие (например, регистрация), удобно использовать invokable контроллер с единственным методом __invoke().

Создание контроллера:

php artisan make:controller RegisterController --invokable

Код контроллера:

<?php

namespace App\Http\Controllers;

use App\Http\Requests\StoreUserRequest;
use App\Services\UserService;

class RegisterController extends Controller
{
    public function __invoke(StoreUserRequest $request, UserService $userService)
    {
        $user = $userService->create($request->validated());

        auth()->login($user);

        return redirect()->route('home');
    }
}

Маршрут:

Route::post('/register', RegisterController::class);

Цель: отсутствие лишних методов, ясность кода.

Проблема: если требуется несколько действий (например, просмотр формы и обработка), invokable не подходит. В этом случае лучше использовать обычный контроллер.

Как вернуть данные пользователя в JSON для API-контроллера?

При разработке API используется контроллер с возвратом JSON. Для форматирования ответа создаются Resource-классы.

Создание ресурса:

php artisan make:resource UserResource

Класс app/Http/Resources/UserResource.php:

<?php

namespace App\Http\Resources;

use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;

class UserResource extends JsonResource
{
    public function toArray(Request $request): array
    {
        return [
            'id'    => $this->id,
            'name'  => $this->name,
            'email' => $this->email,
        ];
    }
}

Пример API-контроллера:

<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Resources\UserResource;
use App\Models\User;

class UserController extends Controller
{
    public function index()
    {
        return UserResource::collection(User::paginate(10));
    }

    public function show($id)
    {
        $user = User::findOrFail($id);
        return new UserResource($user);
    }
}

Цель: единый формат ответа, исключение лишних полей.

Типичная ошибка: возврат коллекции без пагинации приводит к отсутствию мета-данных. Используйте paginate() или collection() с явным указанием ресурса.

Расширенные примеры кода с пояснениями

Пример 1. UserController с FormRequest и сервисным слоем

Полный код трёх компонентов, реализующих создание пользователя с расширенной валидацией и логикой.

Файл app/Http/Requests/StoreUserRequest.php:

Пример
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Password;

class StoreUserRequest extends FormRequest
{
    public function authorize(): bool
    {
        // Можно добавить проверку прав: только admin может создавать
        return $this->user() && $this->user()->isAdmin();
    }

    public function rules(): array
    {
        return [
            'name'            => 'required|string|max:255',
            'email'           => ['required', 'email', 'unique:users,email'],
            'password'        => ['required', 'confirmed', Password::min(8)->letters()->numbers()],
            'role'            => 'sometimes|in:user,admin',
            'profile_picture' => 'nullable|image|mimes:jpg,png|max:2048',
        ];
    }

    public function messages(): array
    {
        return [
            'password.letters' => 'Пароль должен содержать хотя бы одну букву',
            'password.numbers' => 'Пароль должен содержать хотя бы одну цифру',
        ];
    }
}

Файл app/Services/UserService.php:

Пример
<?php

namespace App\Services;

use App\Models\User;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Storage;

class UserService
{
    public function createUser(array $data): User
    {
        // Хешируем пароль
        $data['password'] = Hash::make($data['password']);

        // Сохраняем аватар, если есть
        if (isset($data['profile_picture'])) {
            $path = $data['profile_picture']->store('avatars', 'public');
            $data['profile_picture'] = $path;
        }

        // Создаём пользователя
        $user = User::create($data);

        // Назначаем роль (по умолчанию 'user')
        $user->assignRole($data['role'] ?? 'user');

        return $user;
    }

    public function updateUser(User $user, array $data): bool
    {
        if (isset($data['password'])) {
            $data['password'] = Hash::make($data['password']);
        }

        if (isset($data['profile_picture'])) {
            // Удаляем старый аватар
            if ($user->profile_picture) {
                Storage::disk('public')->delete($user->profile_picture);
            }
            $data['profile_picture'] = $data['profile_picture']->store('avatars', 'public');
        }

        return $user->update($data);
    }

    public function deleteUser(User $user): bool
    {
        // Удаляем аватар
        if ($user->profile_picture) {
            Storage::disk('public')->delete($user->profile_picture);
        }
        return $user->delete();
    }
}

Метод контроллера store():

Пример
public function store(StoreUserRequest $request)
{
    $user = $this->userService->createUser($request->validated());

    return redirect()->route('users.show', $user->id)
                     ->with('success', 'Пользователь создан');
}

Результат: При успешном выполнении пользователь перенаправляется на страницу просмотра созданного пользователя с сообщением. Если валидация не пройдена, Laravel автоматически возвращает предыдущую страницу с ошибками в сессии.

Пример 2. API-контроллер с пагинацией и фильтрацией

Контроллер для REST API, возвращающий список пользователей с возможностью сортировки и фильтрации.

Пример
<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use App\Http\Resources\UserResource;
use App\Models\User;
use Illuminate\Http\Request;

class UserApiController extends Controller
{
    public function index(Request $request)
    {
        $query = User::query();

        // Фильтрация по имени
        if ($request->has('name')) {
            $query->where('name', 'like', '%' . $request->name . '%');
        }

        // Фильтрация по email
        if ($request->has('email')) {
            $query->where('email', $request->email);
        }

        // Сортировка (по умолчанию по id убывание)
        $sortField = $request->get('sort', 'id');
        $sortOrder = $request->get('order', 'desc');
        $query->orderBy($sortField, $sortOrder);

        // Пагинация
        $users = $query->paginate($request->get('per_page', 15));

        return UserResource::collection($users);
    }

    public function store(StoreUserApiRequest $request)
    {
        $user = User::create($request->validated());
        $user->password = bcrypt($request->password);
        $user->save();

        return (new UserResource($user))
                ->response()
                ->setStatusCode(201);
    }

    public function show($id)
    {
        $user = User::findOrFail($id);
        return new UserResource($user);
    }

    public function update(UpdateUserApiRequest $request, $id)
    {
        $user = User::findOrFail($id);
        $user->update($request->validated());
        return new UserResource($user);
    }

    public function destroy($id)
    {
        $user = User::findOrFail($id);
        $user->delete();
        return response()->json(['message' => 'Пользователь удалён'], 200);
    }
}

Пример JSON-ответа для index():

{
    "data": [
        {
            "id": 1,
            "name": "Иван Иванов",
            "email": "ivan@example.com"
        },
        {
            "id": 2,
            "name": "Пётр Петров",
            "email": "petr@example.com"
        }
    ],
    "meta": {
        "current_page": 1,
        "last_page": 3,
        "per_page": 10,
        "total": 25
    }
}

Пояснение шагов:

  • Метод index() принимает параметры name, email, sort, order, per_page.
  • Построитель запросов User::query() применяет фильтры и сортировку.
  • Пагинация через paginate() автоматически добавляет метаданные.
  • Ответ обёрнут в UserResource::collection(), что гарантирует единую структуру.

Пример 3. Использование middleware в контроллере

Добавление проверки роли через middleware прямо в конструкторе контроллера.

Пример
<?php

namespace App\Http\Controllers;

use App\Models\User;
use App\Http\Requests\StoreUserRequest;
use App\Http\Requests\UpdateUserRequest;
use App\Services\UserService;

class UserController extends Controller
{
    public function __construct()
    {
        // Все действия требуют аутентификации
        $this->middleware('auth');

        // Только для действий destroy (админ)
        $this->middleware('can:delete,user')->only('destroy');

        // Только для методов index и show (любой авторизованный)
        $this->middleware('can:view,user')->only(['index', 'show']);
    }

    // ... остальные методы
}

Результат: Доступ к методам контроллера ограничивается в соответствии с политиками (Policies) Laravel. Ошибки авторизации приводят к HTTP-статусу 403.

Важно: Middleware auth проверяет, что пользователь вошёл в систему. can вызывает определённые политики. Для работы необходимо создать политику UserPolicy и зарегистрировать её.

Контроллер пользователя в PHP - comments

En
Controller user php (php)