Laravel 11 api资源PUT请求没有模型的查询结果

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

我正在开发一个使用 Laravel 11 的 API 项目。正如前面提到的,当我在某些端点上发送 PUT 请求时,我收到错误:

“没有该型号的查询结果”

您可以在下面的api.php代码中找到路由:

Route::prefix('area')->middleware('client')->group(function () {

        Route::delete('country', [CountryController::class, 'destroyMultiple']);
        Route::delete('city', [CityController::class, 'destroyMultiple']);
        Route::delete('district', [DistrictController::class, 'destroyMultiple']);
        Route::delete('neighborhood', [NeighborhoodController::class, 'destroyMultiple']);

        Route::apiResource('country', CountryController::class);
        Route::apiResource('city', CityController::class);
        Route::apiResource('district', DistrictController::class);
        Route::apiResource('neighborhood', NeighborhoodController::class);
    });

CountryController
PUT 路由外,每个 PUT 路由都会出现此错误。首先,这是
CountryController
中的工作端点:

public function update(UpdateCountryRequest $request, Country $country)
    {
        DB::transaction(function () use ($request, $country) {
            $country->update($request->only(['country_abbreviation', 'country_code', 'logo', 'status']));

            $delete = [];

            foreach ($request->languages as $language) {
                $countryName = $country->CountryNames()->updateOrCreate([
                    'lang_id' => $language['lang_id'],
                    'country_id' => $country->id,
                ], $language);

                $delete[] = $countryName->id;
            }

            CountryLanguage::where('country_id', $country->id)->whereNotIn('id', $delete)->delete();
        });

        return response()->json([
            'message' => 'Country updated successfully',
            'status' => 'success',
        ]);
    }

还有

UpdateCountryRequest
文件如下:

public function authorize(): bool
{
    if ($this->user()->isAdmin) {
        return true;
    }

    return false;
}


public function rules(): array
{
    $country = $this->route('country');

    return [
        'country_abbreviation' => ['required', 'string', Rule::unique('countries')->ignore($country->id)], // keeping the same country_abbreviation seperately
        'country_code' => ['required', 'string', 'max:5', Rule::unique('countries')->ignore($country->id)],
        'logo' => ['required', 'string', 'max:255'],
        'status' => ['required', 'boolean'],
        'languages' => ['required', 'array'],
        'languages.*.lang_id' => ['required', 'integer', 'exists:languages,id'],
        'languages.*.country_name' => ['required', 'string'],
    ];
}

邮递员 PUT 请求:

enter image description here

但是对于其他控制器,当我发送 PUT 请求时,我收到上述错误:

“没有该型号的查询结果”

例如,让我为您提供

DistrictController
相同的代码:

更新控制器文件内的metot:

 public function update(UpdateDistrictRequest $request, District $district)
    {
        DB::transaction(function () use ($request, $district) {
            $district->update($request->validated());
        });

        return response()->json(['message' => 'District updated successfully'], 200);
    }

UpdateDistrictRequest
代码:

public function authorize(): bool
{
    if ($this->user()->isAdmin) {
        return true;
    }

    return false;
}


public function rules(): array
{
    return [
        'service_id' => 'required|integer',
        'city_id' => 'required|integer|exists:cities,id',
        'name' => 'required|string|max:255',
        'status' => 'required|boolean',
    ];
}

还有邮递员 PUT 请求:

enter image description here

我已经检查了给定 id 的地区是否存在并且它存在于数据库中。

enter image description here

您可以在下面找到迁移:

国家:

Schema::create('countries', function (Blueprint $table) {
            $table->id();
            $table->string('country_abbreviation');
            $table->string('country_code');
            $table->string('logo');
            $table->tinyInteger('status');
            $table->timestamps();
        });

地区:

Schema::create('districts', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('service_id')->nullable();
            $table->unsignedBigInteger('city_id');
            $table->foreign('city_id')->on('cities')->references('id')->onDelete('cascade');
            $table->string('name');
            $table->boolean('status')->default(1);
            $table->timestamps();
        });

还有型号:

国家:

use HasFactory;

    protected $guarded = [];

    protected $fillable = [
        'country_abbreviation',
        'country_code',
        'logo',
        'status'
    ];

// ... Relationship methods

地区:

protected $guarded = [];

    protected $fillable = [
        'service_id',
        'city_id',
        'name',
        'status'
    ];

// ... Relationship methods

当我与 artisan 一起运行“route:list”方法时,我可以看到正确列出的所有放置端点。

我尝试更改 api.php 中的路由定义。例如,将

DistrictCotroller
行移动到其顶部,但当我这样做时,它仍然会同时给出相同的错误
CountryController
请求仍然可以正常工作。

该方法内部抛出异常

src > Illuminate > Routing > ImlicitRouteBinding.php

public static function resolveForRoute($container, $route)
{
    $parameters = $route->parameters();

    $route = static::resolveBackedEnumsForRoute($route, $parameters);

    foreach ($route->signatureParameters(['subClass' => UrlRoutable::class]) as $parameter) {


        if (!$parameterName = static::getParameterName($parameter->getName(), $parameters)) {
            continue;
        }

        $parameterValue = $parameters[$parameterName];

        if ($parameterValue instanceof UrlRoutable) {
            continue;
        }

        $instance = $container->make(Reflector::getParameterClassName($parameter));

        $parent = $route->parentOfParameter($parameterName);

        $routeBindingMethod = $route->allowsTrashedBindings() && in_array(SoftDeletes::class, class_uses_recursive($instance))
            ? 'resolveSoftDeletableRouteBinding'
            : 'resolveRouteBinding';

        if (
            $parent instanceof UrlRoutable &&
            !$route->preventsScopedBindings() &&
            ($route->enforcesScopedBindings() || array_key_exists($parameterName, $route->bindingFields()))
        ) {
            $childRouteBindingMethod = $route->allowsTrashedBindings() && in_array(SoftDeletes::class, class_uses_recursive($instance))
                ? 'resolveSoftDeletableChildRouteBinding'
                : 'resolveChildRouteBinding';

            if (
                !$model = $parent->{$childRouteBindingMethod}(
                    $parameterName,
                    $parameterValue,
                    $route->bindingFieldFor($parameterName)
                )
            ) {
                throw (new ModelNotFoundException)->setModel(get_class($instance), [$parameterValue]);
            }
        } elseif (!$model = $instance->{$routeBindingMethod}($parameterValue, $route->bindingFieldFor($parameterName))) {
            // EXCEPTION
            throw (new ModelNotFoundException)->setModel(get_class($instance), [$parameterValue]);
        }

        $route->setParameter($parameterName, $model);
    }
}

我更改了

CountryController
DistrictController
中的更新方法,如下所示,并注意到在
DistrictController
上,查询数据库不起作用。

// CountryController update
public function update(UpdateCountryRequest $request, int $id)
    {
        dd($id, District::find($id)); // 1, District {#1444 ...}

// DistrictController update
public function update(UpdateDistrictRequest $request, int $id)
    {
        dd($id, District::find($id)); // 1, null

我仔细检查了两个控制器中的命名空间,它们是相同的。

enter image description here

这似乎是由我忽略的

Global Scopes
引起的问题。在我们的模型上,我们有
boot
功能,如下所示,用于将
Global Scopes
注册到服务容器,我相信:

// District Model
protected static function boot()
{
    parent::boot();

    static::addGlobalScope(new FilterBy('App\Services\V1\Area\DistrictFilters', request()->all()));
}

您还可以在下面找到

FilterBy
范围文件代码:

class FilterBy implements Scope
{
    protected $namespace;
    protected $filters;

    public function __construct($namespace, $filters)
    {
        $this->namespace = $namespace;
        $this->filters = $filters;
    }
    /**
     * Apply the scope to a given Eloquent query builder.
     */
    public function apply(Builder $builder, Model $model): void
    {
        $filter = new FilterBuilder($builder, $this->filters, $this->namespace);
        $builder = $filter->apply();
    }
}

也在

FilterBuilder
课程中,我们应用如下过滤器:

public function apply()
    {
        foreach ($this->filters as $name => $value) {
            $normailizedName = ucfirst($name);
            $class = $this->namespace . "\\{$normailizedName}";

            if (! class_exists($class)) {
                continue;
            }

            if (strlen($value)) {
                (new $class($this->query))->handle($value);
            } else {
                (new $class($this->query))->handle();
            }
        }

        return $this->query;
    }

最后我们在给定的

Name.php
命名空间内有
CityId.php
App\Services\V1\Area\DistrictFilters
文件。他们内部有
handle
方法,如下所示:

public function handle($value = ""): void
    {
        // Name.php
        $this->query->where('name', 'ilike','%'. $value .'%');
    }

所以,如果我理解正确的话,当我向 DistrictController 发送

PUT
请求时,因为这些
QueryFilters
除非我发送保存在数据库中的“
Name
”字段,否则它就找不到模型。

例如,我创建了一个

Distrcit
记录,其 Id 为 974,如下所示:

enter image description here

如果我发送如下带有相同“

Name
”的 PUT 请求,它会设法找到模型并更新它:

{
    "service_id" : 1,
    "city_id" : 1,
    "name" : "District",
    "status" : 1
}

但是,如果我发送相同的请求,并使用更新后的名称(例如“

District 123
”),则无法找到模型。

所以我更新了

apply
中的
FilterBy
函数,如下所示,以防止添加
QueryFilters
,这似乎解决了问题:

public function apply(Builder $builder, Model $model): void
    {
        if (collect(['PUT', 'PATCH'])->contains(request()->method())) {
            return;
        }
        
        $filter = new FilterBuilder($builder, $this->filters, $this->namespace);
        $builder = $filter->apply();
    }

如果我分享了整个

District
模型代码,找到问题会更快。是我不好。谢谢大家的努力帮助。

php laravel eloquent
1个回答
3
投票

我们在之前的项目中也遇到过这样的错误。如果您使用范围,这些范围可能会影响 put 和 patch 选择查询。

查看查询预览;

//DistrictController

public function update(UpdateDistrictRequest $request, int $id)
{
    District::dd();

如果问题是由作用域引起的,您可以跳过 put 和 patch 请求方法的作用域。

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