Принцип ПОКОЯ метода PUT в Laravel

#php #laravel #rest #http

Вопрос:

Я готовлю общий и текущий REST API типа CRUD с users моделью, которую по умолчанию использует laravel

 <?php

namespace AppModels;

use LaravelSanctumHasApiTokens;
use IlluminateNotificationsNotifiable;
use IlluminateContractsAuthMustVerifyEmail;
use IlluminateDatabaseEloquentFactoriesHasFactory;
use IlluminateFoundationAuthUser as Authenticatable;
use IlluminateAuthPasswordsCanResetPassword;

class User extends Authenticatable implements MustVerifyEmail {

  use HasApiTokens, HasFactory, Notifiable, CanResetPassword;

  /**
   * The attributes that are mass assignable.
   *
   * @var string[]
   */
  protected $fillable = [
      'name',
      'email',
      'password'
  ];

  /**
   * The attributes that should be hidden for serialization.
   *
   * @var array
   */
  protected $hidden = [
      'password',
      'remember_token',
  ];

  /**
   * The attributes that should be cast.
   *
   * @var array
   */
  protected $casts = [
      'email_verified_at' => 'datetime'
  ];
}
 

и маршруты, которые я генерирую с помощью Route::apiResource

 Route::apiResource('users', UserController);
 

Поскольку я хочу найти пользователя с помощью email или id я делаю ссылку или явное введение параметра маршрута RouteServiceProvider внутри метода boot с помощью Route::bind

 Route::bind('user', function($userId){

  $user = User::where(fn($query) => $query->where('id', $userId)->orWhere('email', $userId))->first();
  if(request()->method() === 'PUT') return $user;
  return $userId;
});

 

Это где главной темой приходит в этот метод ( Route::bind () ) должен возвращать экземпляр класса, если нет, он вернется ExceptionModelNotFound 404 - not found , но я хотел бы быть в состоянии появиться null в мой контроллер и таким образом проверяют в зависимости от метода (или поставить патч), требуется ли создавать новую запись (которая согласно остальные принципы должны быть в состоянии сделать ресурс, если нет соответствия) или обновить существующую.

Мой update метод UserController заключается в следующем

 public function update(Request $request, User $user){

  $input = $request->all();
  $method = $request->method();
  if($method === 'PUT') $request->validate($this->rules);

  $update = [
    'PUT' => fn() => ($user) ? $user->update($input) : $user = $user::create($input),
    'PATCH' => function() use($user, $input){

      foreach ($input as $key => $val){
        $user->$key = (!empty($val)) ? $val : $user->$key;
      }
      $user->save();
      return $user;
    }
  ];
  return response()->json($update[$method]());
}
 

Раньше у меня это было без инъекции модели, и метод ùpdate работал, что-то вроде этого

 public function update(Request $request, $user){
 

Но из — за явной инъекции это больше не принимает параметр, кроме того, меня интересует только такое поведение при обновлении, так как это в остальных методах помогает сократить код, и это нормально для обработки 404-Не найдено.
Я не знаю, проваливаюсь ли я в чем-то или, может быть, laravel предлагает лучший способ сделать это, которого я не знаю.

Заранее спасибо.

PS: Код немного абстрагирован, он выглядит немного запутанным, потому что я попытался его упростить.

Ответ №1:

Вы не облегчаете себе задачу, создавая одно действие контроллера как для обновления, так и для создания пользователей. Я никогда не делал этого таким образом и всегда определяю ОСТАЛЬНЫЕ маршруты так:

  • PUT /user/1 = ОБНОВЛЕНИЕ
  • POST /user = СОЗДАТЬ

Вы должны знать на интерфейсе, создаете ли вы нового пользователя или обновляете существующего (например, просто проверьте наличие id элемента).

Кроме того, привязка вашего текущего маршрута не является лучшей логикой, поскольку этот $user запрос всегда выполняется, даже если он не является PUT запросом. Тем не менее, этот код может быть значительно упрощен, если вы используете только firstOrFail() этого пользователя, так как в любом случае вы должны разделить функциональность на 2 маршрута.

Лично я никогда не использую PATCH , так как мои PUT маршруты также допускают частичные обновления (например, только отправку email обновления свойств).

Комментарии:

1. Спасибо, что ответили на Flame, ну, я попытался сделать это таким образом, потому что ОСТАЛЬНЫЕ принципы говорят, что с помощью метода ИСПРАВЛЕНИЯ выполняется частичное обновление, а с помощью метода PUT-полное обновление, и если строка, идентифицированная каким-либо уникальным столбцом, не существует, она создана. Что касается маршрутов, я создал их с помощью метода ApiResource, поэтому каждая операция обрабатывается своим методом, но я сомневался, почему laravel с ApiResource () предоставляет два маршрута (PUT и PATCH), которые указывают на контроллер метода обновления? это просто для того, чтобы выбрать предпочтительный метод ?.

2. А что касается привязки маршрута, я просто хотел проверить, существует ли она, вернуть строку, если нет, вернуть значение null, чтобы справиться с собой в контроллере.

3. Но все же спасибо, что ответили мне и рассказали о своем способе работы. Если нет возможности или это не принято на рабочем месте, я сделаю это проще.