Появилась задача - сделать так, чтобы через определенные маршруты API не были доступны определенные элементы по критерию. Решил сделать с помощью применения глобального скоупа к моделям, написал middleware:
AddApiScopes.php
<?php
namespace App\Http\Middleware;
use App\Models\Order;
use Closure;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;
class AddApiScopes
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle(Request $request, Closure $next)
{
Order::addGlobalScope('active', function (Builder $builder) {
$builder->where('status', '<>', 0);
});
return $next($request);
}
}
добавил его к группе маршрутов:
api.php
Route::prefix('/')->middleware(AddApiScopes::class)->group(function () {
//...
Route::get('orders', [ApiController::class, 'orders']);
Route::get('orders/{order}', [ApiController::class, 'order']);
//...
});
В методе 'orders' все работает, отображаются только элементы с нужными статусами
public function orders()
{
return OrderResource::collection(Order::all()); // тут скоуп применяется
}
Однако в методе order, если в адресной строке вручную прописать id элемента с неправильным статусом - ошибка 404 не выдается, приходится дублировать код. Это грозит тем, что я забуду прописать этот код в каком-то месте, или могут быть косяки при изменении условий.
public function order(Order $order)
{
if ($order->status === 0) { // костыль
abort(404);
}
return new OrderResource($order);
}
Как сделать так, чтобы глобальный скоуп отрабатывал и для разрешения модели и я даже не попадал в эту процедуру?
Пока дошел до такого костыля:
Route::get('test/{order_id}', function ($order_id) { // выдает 404
$order = Order::findOrFail($order_id);
return $order;
});
Route::get('test2/{order}', function (Order $order) { // выдает данные модели
return $order;
});
но хочется, чтобы работал
https://laravel.com/docs/8.x/routing#implicit-binding