Laravel 没有全局范围的路由模型绑定
Laravel route model binding without global scope
我的 laravel 8.0 应用程序中有以下路线组:
Route::prefix('offline_transaction')->name('offline_transaction.')->group(function () {
Route::post('/approve/{transaction:uuid}', [OfflineTransactionController::class, 'approve'])
->name('approve');
Route::post('/reject/{transaction:uuid}', [OfflineTransactionController::class, 'reject'])
->name('reject');
});
而Transaction
模型是:
class Transaction extends Model implements CreditBlocker
{
//....
protected static function boot()
{
parent::boot();
static::addGlobalScope(new AuthUserScope());
}
//....
}
这是我的 AuthUserScope
:
class AuthUserScope implements Scope
{
private string $fieldName;
public function __construct($fieldName = 'user_id')
{
$this->fieldName = $fieldName;
}
public function apply(Builder $builder, Model $model)
{
$user = Auth::user();
if ($user) {
$builder->where($this->fieldName, $user->id);
}
}
}
现在的问题是,当管理员想要批准或拒绝 transaction
时,将抛出 404 Not found 错误。我怎样才能通过这个?
Customizing The Resolution Logic
If you wish to define your own model binding resolution logic, you may
use the Route::bind
method. The closure you pass to the bind
method will receive the value of the URI segment and should return the
instance of the class that should be injected into the route. Again,
this customization should take place in the boot
method of your
application's RouteServiceProvider
:
解决方案
您可以做的是更改 routes/web.php
文件中特定路线的参数名称。
Route::prefix('offline_transaction')->name('offline_transaction.')->group(function () {
Route::post('/approve/{any_transaction}', [OfflineTransactionController::class, 'approve'])
->name('approve');
Route::post('/reject/{any_transaction}', [OfflineTransactionController::class, 'reject'])
->name('reject');
注意 any_transaction
。将其更改为您认为最方便的任何命名约定。
然后,在您的 app/Providers/RouteServiceProvider.php
文件中,将您的 boot(...)
方法更改为如下内容:
use App\Models\Transaction;
use Illuminate\Support\Facades\Route;
// ...
public function boot()
{
// ...
Route::bind('any_transaction', function($uuid) {
return Transaction::withoutGlobalScopes()->where('uuid', $uuid)->firstOrFail();
});
// ...
}
// ...
然后在您的控制器 app/Http/Controllers/OfflineTransactionController.php
文件中,访问注入的模型:
use App\Models\Transaction;
// ...
public function approve(Transaction $any_transaction) {
// ...
}
// ...
致谢:Using Route Model Binding without Global Scope @thomaskim
附录
如果你想remove a specific global scope从路由模型绑定查询,你可以使用
withoutGlobalScope(AuthUserScope::class)
在 app/Providers/RouteServiceProvider.php
文件的 boot(...)
方法中。
另一种方法是我可以在 AuthUserScope
class 中使用 Route::currentRouteNamed
如下,我更喜欢使用它而不是 Route::bind
:
<?php
namespace App\Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
class AuthUserScope implements Scope
{
private string $fieldName;
public function __construct($fieldName = 'user_id')
{
$this->fieldName = $fieldName;
}
public function apply(Builder $builder, Model $model)
{
$user = Auth::user();
if ($user && !Route::currentRouteNamed('admin.*')) {
$builder->where($this->fieldName, $user->id);
}
}
}
我的 laravel 8.0 应用程序中有以下路线组:
Route::prefix('offline_transaction')->name('offline_transaction.')->group(function () {
Route::post('/approve/{transaction:uuid}', [OfflineTransactionController::class, 'approve'])
->name('approve');
Route::post('/reject/{transaction:uuid}', [OfflineTransactionController::class, 'reject'])
->name('reject');
});
而Transaction
模型是:
class Transaction extends Model implements CreditBlocker
{
//....
protected static function boot()
{
parent::boot();
static::addGlobalScope(new AuthUserScope());
}
//....
}
这是我的 AuthUserScope
:
class AuthUserScope implements Scope
{
private string $fieldName;
public function __construct($fieldName = 'user_id')
{
$this->fieldName = $fieldName;
}
public function apply(Builder $builder, Model $model)
{
$user = Auth::user();
if ($user) {
$builder->where($this->fieldName, $user->id);
}
}
}
现在的问题是,当管理员想要批准或拒绝 transaction
时,将抛出 404 Not found 错误。我怎样才能通过这个?
Customizing The Resolution Logic
If you wish to define your own model binding resolution logic, you may use the
Route::bind
method. The closure you pass to thebind
method will receive the value of the URI segment and should return the instance of the class that should be injected into the route. Again, this customization should take place in theboot
method of your application'sRouteServiceProvider
:
解决方案
您可以做的是更改 routes/web.php
文件中特定路线的参数名称。
Route::prefix('offline_transaction')->name('offline_transaction.')->group(function () {
Route::post('/approve/{any_transaction}', [OfflineTransactionController::class, 'approve'])
->name('approve');
Route::post('/reject/{any_transaction}', [OfflineTransactionController::class, 'reject'])
->name('reject');
注意 any_transaction
。将其更改为您认为最方便的任何命名约定。
然后,在您的 app/Providers/RouteServiceProvider.php
文件中,将您的 boot(...)
方法更改为如下内容:
use App\Models\Transaction;
use Illuminate\Support\Facades\Route;
// ...
public function boot()
{
// ...
Route::bind('any_transaction', function($uuid) {
return Transaction::withoutGlobalScopes()->where('uuid', $uuid)->firstOrFail();
});
// ...
}
// ...
然后在您的控制器 app/Http/Controllers/OfflineTransactionController.php
文件中,访问注入的模型:
use App\Models\Transaction;
// ...
public function approve(Transaction $any_transaction) {
// ...
}
// ...
致谢:Using Route Model Binding without Global Scope @thomaskim
附录
如果你想remove a specific global scope从路由模型绑定查询,你可以使用
withoutGlobalScope(AuthUserScope::class)
在 app/Providers/RouteServiceProvider.php
文件的 boot(...)
方法中。
另一种方法是我可以在 AuthUserScope
class 中使用 Route::currentRouteNamed
如下,我更喜欢使用它而不是 Route::bind
:
<?php
namespace App\Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Route;
class AuthUserScope implements Scope
{
private string $fieldName;
public function __construct($fieldName = 'user_id')
{
$this->fieldName = $fieldName;
}
public function apply(Builder $builder, Model $model)
{
$user = Auth::user();
if ($user && !Route::currentRouteNamed('admin.*')) {
$builder->where($this->fieldName, $user->id);
}
}
}