У меня есть модель User
, и это мой метод update()
в UserController
:
public function update(Request $request, User $user)
{
// Assign authorization
Gate::authorize('update', $user);
$request->validate([
'username' => 'required|unique:users,username,' . $user->id,
// other rules ...
]);
// ...
}
Я хочу сохранить эти правила проверки в отдельном UpdateUserRequest
запросе:
class UpdateUserRequest extends FormRequest
{
public function authorize(): bool
{
return true; // Changed to 'true' to handle authorization logic in UserPolicy
}
public function rules(): array
{
return [
'username' => 'required|unique:users,username,' . $user->id, // <-- Problem
// other rules ...
];
}
}
Проблема здесь в том, что $user
не определен. Я читал в другом месте, что использование маршрута для этого вопроса является возможным решением, но это не правильный способ решения этой задачи.
Мой вопрос: как правильно передать информацию о пользователе в класс UpdateUserRequest
?
@matiaslauriti Что делать, если в систему вошел не тот пользователь?
@Zakk, можешь ли ты поделиться определением своего маршрута для этого? Используете ли вы неявную привязку модели при определении маршрута?
@Zakk, я опубликовал свой ответ, пожалуйста, проверьте и дайте мне знать ваш отзыв. Спасибо
@Zakk, ты никогда не говорил в своем вопросе, что у тебя может не быть зарегистрированного пользователя...
@matiaslauriti Какое это имеет отношение к теме? Как эта информация может повлиять на ответ? И с каких это пор вход пользователей в систему или не влияет на другие модели?
@Закк, откуда я могу знать, что auth()->id()
не будет работать, если ты не скажешь мне, что пользователь может существовать? В исходном коде вы получаете пользователя каждый раз...
Мой вопрос в том, как правильно передать информацию о пользователе в Класс UpdateUserRequest?
Я предположил, что вы используете laravel 11.X, и ваше определение маршрута...
Route::put('/users/{user}', [UserController::class, 'update']);
В этом сценарии вы можете сделать это внутри UpdateUserRequest
.
class UpdateUserRequest extends FormRequest
{
public function authorize(): bool
{
// Here you can also interact with your `gates` & `policy`,Check the docs link I provided below to get clear insights.
return true;
}
public function rules(): array
{
//Scenario 1
$user = User::find($this->route('user')); //If you are not using `implicit model binding`
//Scenario 2
$user = $this->user ; //If you are using `route-model-binding`
return [
'username' => 'required|unique:users,username,' . $user->id, // <-- "Issue will be solved"
// other rules ...
];
}
}
Затем в классе контроллера import
и type-hint
класс FormRequest, т. е. UpdateUserRequest
в вашем методе контроллера, который отсутствует в вашем текущем коде.
public function update(UpdateUserRequest $request, User $user)
{
// Assign authorization
Gate::authorize('update', $user);
// Retrieve the validated input data...
$validated = $request->validated(); // it will by default validate all the input data you set up in the `rule()` of `UpdateUserRequest`
// ...
}
Для получения более четкой и глубокой информации ознакомьтесь с официальной документацией здесь.
Я предпочитаю иметь дело с логикой авторизации в классах политики. В противном случае код будет немного запутанным, поскольку некоторые его части будут находиться в запросах, некоторые — в контроллерах (Gate::authorize()
).
Вот как я определил свои маршруты: Route::resource('users', UserController::class);
@Zakk, Основная логика останется прежней, и да, вы можете разделить логику авторизации в классах политики, проблем не будет. Если вы используете Route::resource('users', UserController::class);
, он по умолчанию будет обрабатывать привязку модели маршрута. Попробуйте ответить и дайте мне знать, если вы где-нибудь застряли. А также перейдите по ссылке на документацию, которую я предоставил в ответе, где вы получите более подробную информацию.
Это сработало. Спасибо! Итак, дело в том, что классы UpdateModelRequest
и StoreModelRequest
имеют «известную» им модель.
У меня есть еще два вопроса. Ответ: Необходимо ли использовать validated()
для запуска проверки? Или это делается автоматически? Б: Чтобы использовать проверенные данные, можно ли просто использовать $request->username
или необходимо использовать функцию validated
?
@Zakk, согласно официальным документам, когда вы используете запрос пользовательской формы, например UpdateModelRequest
, вы должны вызвать $request->validated();
, чтобы получить проверенные данные. И когда вы используете объект Illuminate\Http\Request
по умолчанию, вам нужно использовать $request->validate([ ])
и внутри массива передать все поля проверки в паре ключ-значение массива. проверьте ссылку 1) laravel.com/docs/11.x/… 2) для запроса пользовательской формы проверьте это: - laravel.com/docs/11.x/validation#creating-form-requests
В этом случае, как получить файлы (например, $request->hasFile('field')
) по проверенным запросам, поскольку они представляют собой простые массивы?
«Необходимо ли использовать validated() для запуска проверки» — при использовании запросов формы НЕТ проверка все равно выполняется до того, как будет обработан ваш контроллер, это означает, что ваша проверка выполняется до проверки Gate::authorize
. Поэтому авторизацию лучше обрабатывать в самом запросе формы.
«Чтобы использовать проверенные данные, можно просто использовать $request->username или они должны использовать проверенную функцию» — вы можете использовать $request->$field
, но нет никакой гарантии, что $field
было проверено, а использование $request->validated()[$field]
приведет к ошибке отсутствия ключа, если $field
не был ключевым в списке правил.
А как насчет авторизации для других методов, таких как создание и удаление? Должны ли они обрабатываться в контроллере или где-то еще?
@Zakk, Да, вы можете обрабатывать create
и delete
так же, как и update
. Для создания есть небольшая разница, вы можете проверить эту ссылку 1) laravel.com/docs/11.x/authorization#methods-without-models Для delete
вы можете следовать той же логике, что и для update
, проверьте ссылку 2) laravel.com/docs/11.x/authorization#policy-methods
Вы не поняли мой вопрос. В случае store
и update
проверку авторизации лучше выполнять в классах запросов. А как насчет авторизации для create
и delete
? Должен ли Gate::authorize('create', User::class)
присутствовать в методе контроллера create
?
@Zakk, «Должны ли они обрабатываться в контроллере или где-то еще?», вы также можете обработать это в маршруте, используя can()
как промежуточное программное обеспечение, а также в контроллере.
В моем случае я не могу использовать can()
в качестве промежуточного программного обеспечения, потому что я использую Route::resource('users', UserController::class);
@Zakk, в этом случае вам нужно использовать метод Gate::authorize('create', User::class)
внутри контроллера, возникнет проблема с np. Здесь метод политики create
не требует экземпляра модели. Проверьте здесь: - laravel.com/docs/11.x/…
У вас есть
auth()->user()->id
или прощеauth()->id()