我正在开发一个使用 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 请求:
但是对于其他控制器,当我发送 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 请求:
我已经检查了给定 id 的地区是否存在并且它存在于数据库中。
您可以在下面找到迁移:
国家:
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
我仔细检查了两个控制器中的命名空间,它们是相同的。
这似乎是由我忽略的
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,如下所示:
如果我发送如下带有相同“
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
模型代码,找到问题会更快。是我不好。谢谢大家的努力帮助。
我们在之前的项目中也遇到过这样的错误。如果您使用范围,这些范围可能会影响 put 和 patch 选择查询。
查看查询预览;
//DistrictController
public function update(UpdateDistrictRequest $request, int $id)
{
District::dd();
如果问题是由作用域引起的,您可以跳过 put 和 patch 请求方法的作用域。