Laravel 路由模型绑定没有全局作用域

问题描述 投票:0回答:4

我的 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 错误。我怎样才能通过这个?

laravel laravel-8
4个回答
4
投票

自定义解析逻辑

如果您想定义自己的模型绑定解析逻辑,您可以 使用

Route::bind
方法。您传递给
bind
的闭包 方法将接收 URI 段的值并应返回 应注入到路由中的类的实例。再次, 此定制应该在您的
boot
方法中进行 应用程序的
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) {

// ...

}

// ...

鸣谢:在没有全局作用域的情况下使用路由模型绑定@thomaskim

附录

如果您想从路由模型绑定查询中删除特定的全局范围,您可以使用

withoutGlobalScope(AuthUserScope::class)
boot(...)
文件的
app/Providers/RouteServiceProvider.php
方法中。


3
投票

另一种方法是我可以在

Route::currentRouteNamed
类中使用
AuthUserScope
,如下所示,我更喜欢使用它而不是
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);
        }
    }
}

2
投票

我们也可以这样做。

 /**
     * Retrieve the model for a bound value.
     *
     * @param  mixed  $value
     * @param  string|null  $field
     * @return \Illuminate\Database\Eloquent\Model|null
     */
    public function resolveRouteBinding($value, $field = null)
    {
        return $this->withoutGlobalScopes()->where($field ?? $this->getRouteKeyName(), $value)->first();
    }

在上面的代码中,我们实际上重写了模型文件中现有的方法,该方法在 Laravel 中的每个模型类中扩展。

只需在现有查询中添加

withoutGlobalScopes
即可正常工作。


0
投票

在我的具体情况下,我想删除全局作用域,同时仍然保留子关系的隐式作用域。

我通过以下方式实现了这一点

routes/web.php

Route::get('/parents/{parent}/children/{child:id}/'[
    \App\Http\Controllers\ChildrenController::class, 'show'])
    ->name('showAllChildren');

模型/Child.php

use Illuminate\Support\Facades\Route;

public function resolveRouteBindingQuery($query, $value, $field = null)
    {
        if(Route::currentRouteNamed('showAllChildren')){
            return $query->withoutGlobalScope()->where($field ?? $this->getRouteKeyName(), $value);
        }
        return parent::resolveRouteBindingQuery($query, $value, $field);
    }

这允许我忽略此路由上的全局应用范围,同时仍然使用具有自定义键范围的隐式路由模型绑定。

© www.soinside.com 2019 - 2024. All rights reserved.