@lexstile

Как в laravel правильно запретить редактирование сущности по условию?

Задача:
1. Cделать так, чтобы при валидации status срабатывала еще и ф-ция из модели canChangeStatus, которая говорит, в какой статус можно переводить заказ в текущий момент.
2. А также, чтобы срабатывала на обновление ф-ция из модели canUpdate, которая бы говорила, что заказ редактировать можно.

И хотелось бы это разрулить в OrderUpdateRequest.

Есть мысли/идеи, как это грамотно можно разрулить?

OrderUpdateRequest
class OrderUpdateRequest extends FormRequest
{

    public function rules()
    {
        switch ($this->getMethod())
        {
            case 'PATCH':
                return [
                    'table_id' => ['numeric', 'exists:tables,id'],
                    'user_id' => ['numeric', 'exists:users,id'],
                    'status' => ['string', 'in:'. Order::NEW.','.Order::WORK.','.Order::CLOSE.','.Order::PAID],
                ];
            case 'PUT':
                return [
                    'table_id' => ['required', 'numeric', 'exists:tables,id'],
                    'user_id' => ['required', 'numeric', 'exists:users,id'],
                    'status' => ['required', 'string', 'in:'. Order::NEW.','.Order::WORK.','.Order::CLOSE.','.Order::PAID],
                ];
        }
    }

    protected function prepareForValidation()
    {
        $this->merge([
            //
        ]);
    }

    public function failedValidation(Validator $validator)
    {
        throw new HttpResponseException(response()->json([
            'success' => false,
            'errors' => $validator->errors(),
        ])->setStatusCode(400));
    }
}

Order
class Order extends Model
{
    use HasFactory, SoftDeletes;

    const NEW = 'new';
    const WORK = 'work';
    const CLOSE = 'close';
    const CANCEL = 'cancel';
    const PAID = 'paid';

    protected $fillable = [
        'project_id',
        'table_id',
        'user_id',
        'status',
    ];

    public function dishes()
    {
        return $this->belongsToMany(Dishe::class)->withTimestamps();
    }

    public function canChangeStatus($status)
    {
        switch ($this->status) {
            case self::NEW: return $status === self::WORK || $status === self::CANCEL;
            case self::WORK: return $status === self::PAID || $status === self::CANCEL;
            case self::PAID: return $status === self::CLOSE || $status === self::CANCEL;
        }

        return false;
    }

    public function canUpdate() {
        if (in_array($this->status, [self::NEW, self::WORK, self::PAID])) {
            return true;
        }
    
        return false;
    }
}

OrderController
class OrderController extends BaseController
{
    public function update(OrderUpdateRequest $request, Project $project, Order $order)
    {
        $order->fill($request->all());
        $order->saveOrFail();

        return $this->baseJson(message: ResponseHelper::success(__('orders.messages.updated')));
    }
}
  • Вопрос задан
  • 235 просмотров
Решения вопроса 2
iMedved2009
@iMedved2009
Не люблю людей
class OrderUpdateRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize(): bool
    {
        return $this->order->canChangeStatus($this->get('status'))&&$this->order->canUpdate();
    }
}


Не надо так:

switch ($this->getMethod())
        {
            case 'PATCH':
                return [
                    'table_id' => ['numeric', 'exists:tables,id'],
                    'user_id' => ['numeric', 'exists:users,id'],
                    'status' => ['string', 'in:'. Order::NEW.','.Order::WORK.','.Order::CLOSE.','.Order::PAID],
                ];
            case 'PUT':
                return [
                    'table_id' => ['required', 'numeric', 'exists:tables,id'],
                    'user_id' => ['required', 'numeric', 'exists:users,id'],
                    'status' => ['required', 'string', 'in:'. Order::NEW.','.Order::WORK.','.Order::CLOSE.','.Order::PAID],
                ];
        }
Ответ написан
@jazzus
Грамотно - не заниматься проверкой прав в модели. Юзать политики авторизации и обрабатывать 403 на фронте. Убрать failedValidation т.к. Ларавел сам составит правильный ответ. Success не нужно, если есть ошибки значит не success. Убрать бессмысленные проверки в rules с одинаковым кодом. Использовать ларавелевский response в контроллере без оберток и велосипедов.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы