解决此问题的正确(大多数 Laravel)方法是啥(如果有)
Posted
技术标签:
【中文标题】解决此问题的正确(大多数 Laravel)方法是啥(如果有)【英文标题】:What is the correct (most Laravel) approach to this probem (if any)解决此问题的正确(大多数 Laravel)方法是什么(如果有) 【发布时间】:2021-07-11 12:14:32 【问题描述】:在我的应用程序中,我有一个像这样名为“Order”的模型,遵循默认的 Laravel 行为,并带有一个名为“hash”的附加唯一字符串属性:
class Order extends Model
// $table = 'orders';
// $primaryKey = 'id';
// $incrementing = true;
$hash = 'a1b2c3d4e5f6g7h8i9';
// many related models
函数 Model::find 的默认行为是查找主键,这是我绝对想要保留的功能。目前我的 routes/api.php 包含这样的功能:
public function show(Request $request, Order $order)
// the order will be loaded via the id
// if the model is not found an exception is thrown
在某些情况下,我现在想注入相同的订单,但通过订单的哈希进行搜索,所以我假设我的 api.php 看起来像这样:
public function show(Request $request, OrderSearchByHash $order)
// the order will be loaded via the id
// if the model is not found an exception is thrown
问题来了:这是否可以实现?如果可以,如何实现?我实际上并不需要源代码,而是提示我必须去的方向。我已经阅读了有关 ServiceProviders 和 Facades 的内容,尝试创建扩展模型(但我必须“修补”所有关系,因为数据透视表会有不同的名称)以及 Laravel 文档中的许多其他内容,但我仍然没有甚至确切地知道是否涵盖了我的具体问题?
有人给我提示吗? 提前致谢!
【问题讨论】:
这有点不清楚。为什么show
方法应该知道订单是通过 ID 还是哈希搜索的?会有什么不同?
据我了解文档(在这种情况下我可能完全偏离主题),服务提供商通过类型提示识别我请求的模型并为我加载它。我想要它做的仍然是寻找一个订单模型,但不是通过 ID,而是通过哈希。我希望只更改控制器中的注入类型,检索与通过 ID 搜索时完全相同的模型,并继续使用我当前使用的相同源代码。
是的,但是在这两种情况下,您的控制器方法都应该收到Order
。获取它的方式不应该改变它的类型。您可能想要做的是更改到该控制器方法的路由的构造方式,例如route('show', [Order::firstWhere('hash', $hash)])
。
【参考方案1】:
您可以使用自定义模型绑定:
您的控制器中的两个方法都将如下所示:
public function show(Request $request, Order $order)
Route::get('orders/order', 'OrderController@show');
Route::get('orders-by-hash/order_by_hash', 'OrderController@show');
Route::bind('order_by_hash', function ($value)
// Use your logic for finding your order by hash
return Order::where[...]->first();
);
您也可以授权仅在连接时通过 ID 查找订单:
Route::bind('order', function ($value)
// Use your logic for finding your order by hash
return Order::where[...]->when(auth()->check(), function()
$query->orWhere(function($query)
$query->where(order_id, $value)
->where(user_id, auth()->id());
)
)->first();
);
So when you are connected, IF an order with the id belongs to the user , you can find it that way
This is only relevant if your route using an id and your hash are using the same controller's methods, else I recommend to use 2 different model bindings
【讨论】:
这对于一条路线来说是一个可行的解决方案,但我忘了提到订单模型至少在二十条路线中使用,我必须更改每一条路线。这就是我想改变注射的原因之一,我希望它是最简单的(也是最简单的方式) 这是列表 laravel 方式,因为如果您使用相同的路由模型名称(order),那么使用 id 或哈希会给您一个模型,我认为您的哈希应该是混淆你的订单的id,这样人们就不能用orders/1找到它,所以最简单的方法是使用order为内部使用提供路由(当你登录时,你可以检查你是否可以访问订单) 并使用 order_by_hash 为您的公共访问路由。您也可以始终使用您的哈希路由,但如果您已连接,那么您可以使用 ID 找到它,我将编辑我的答案以显示它 我是否正确理解了 Route::bind 改变了任何 URL 中名为 order 的变量的解释方式?这就是我可以决定通过 primaryKey 还是哈希搜索模型的方式?【参考方案2】:您可以创建一个条件,其中id
是 PK 或哈希。然后根据得到的id
的类型进行查询。
例如:
Route::get('orders/id', [OrderController::class, 'show']);
public function show(Request $request, $id)
$type = ctype_alnum($id) ? 'hash' : 'pk'; // or another checking method
$item = $type == 'pk'
? Order::find($id)
: Order::where('hash', $id)->first();
...
【讨论】:
【参考方案3】:@Mathieu:感谢 Route::bind 的提示,我最终在 RouteServiceProvider 中得到了这个
Route::bind('order', function($value)
if((int)$value > 0 && env('APP_ENV', 'production') == 'dev')
return Order::find($value);
return Order::where('hash', (string)$value)->first();
);
我允许在开发环境中使用 ID,以便我可以使用 Postman 更轻松地测试 API。
再次:非常感谢!
【讨论】:
laravel.com/docs/8.x/routing#customizing-the-resolution-logic 我实际上切换到在实际订单模型中使用“公共函数 resolveRouteBinding()”,如果我需要第二个模型来使用不同的搜索键而不是主键以上是关于解决此问题的正确(大多数 Laravel)方法是啥(如果有)的主要内容,如果未能解决你的问题,请参考以下文章
在 laradock 中安装 laravel 的正确方法是啥?
在 laravel 中将“历史数据”存储到数据库中的正确方法是啥?