laravel - Laravel 与资源的关系-> 试图获取非对象的属性“id”
问题描述
我试图从高处和低处寻找解决方案,但失败了。所以这里是:
我正在为网站制作照片库模块。我有一个名为“GalleryName”的模型和另一个名为“GalleryPhoto”的模型,并在它们之间建立了 hasMany 关系。
我正在使用 Vue JS 和我用来显示照片的包要求我使用单词“title”作为照片名称的键,并使用“src”作为我存储的文件的完整路径的键。我决定使用资源文件来更改键和值,而不是更改我的数据库和其他逻辑。
首先,这是我的迁移:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateGalleryNamesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('gallery_names', function (Blueprint $table) {
$table->id();
$table->string('gallery_name');
$table->string('gallery_cover_photo');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('gallery_names');
}
}
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateGalleryPhotosTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('gallery_photos', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('gallery_name_id');
$table->string('photo_title');
$table->string('photo_image');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('gallery_photos');
}
}
这是我的模型:
// Gallery Name
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class GalleryName extends Model
{
use HasFactory;
protected $guarded = [];
public function gallery_photos(){
return $this->hasMany(GalleryPhoto::class);
}
}
// Gallery Photo
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class GalleryPhoto extends Model
{
use HasFactory;
protected $guarded = [];
public function gallery_name(){
return $this->belongsTo(GalleryName::class);
}
}
这是我的资源文件:
// Gallery Name Resource
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class GalleryNameResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
// return parent::toArray($request);
return [
'id' => $this->id,
'gallery_name' => $this->gallery_name,
'gallery_cover_photo' => $this->gallery_cover_photo,
'created_at' => $this->created_at,
'gallery_photos' => GalleryPhotoResource::collection($this->gallery_photos)
];
}
}
我正在使用这一行,'gallery_photos' => GalleryPhotoResource::collection($this->gallery_photos),因为当您需要在关系中使用资源时,文档会告诉您这样做。
// Gallery Photo Resource
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class GalleryPhotoResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
// return parent::toArray($request);
return [
'id' => $this->id,
'gallery_name_id' => $this->gallery_name_id,
'title' => $this->photo_title,
'src' => '/storage/photo_gallery_images/'.$this->photo_image,
'created_at' => $this->created_at,
];
}
}
我正在使用这一行,'src' => '/storage/photo_gallery_images/'.$this->photo_image,因为我只将文件名存储在数据库中,现在我需要完整的限定路径,而不仅仅是我的包中的文件名要求。
我在控制器中声明了一个 show 方法,如下所示:
// Gallery Name Controller
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\GalleryName;
use App\Http\Resources\GalleryNameResource;
class GalleryNameController extends Controller
{
public function show($id)
{
$gallery_name = new GalleryNameResource(GalleryName::where('id', $id)->select('id', 'gallery_name','gallery_cover_photo' , 'created_at')->with(['gallery_photos' => function($query) {
return $query->select(['id', 'gallery_name_id', 'photo_title', 'photo_image', 'created_at']);
}])->first());
if($gallery_name){
return response()->json($gallery_name, 200);
}
return response()->json('Gallery Not Found !!', 404);
}
}
如您所见,这是使用关系,但也使用了我之前声明的资源文件。
现在,当我使用 Postman 并提供存在的 id(作为路由参数)时,它会显示正确的 JSON 响应。例如
{
"id": 1,
"gallery_name": "Some Gallery 1",
"gallery_cover_photo": "pexels-lena-goncharova-8692688-400x300_1628567178.jpg",
"created_at": "2021-08-10T03:46:18.000000Z",
"gallery_photos": [
{
"id": 1,
"gallery_name_id": 1,
"title": "Photo 1",
"src": "/storage/photo_gallery_images/pexels-lena-goncharova-8692688-900x800_1628567237.jpg",
"created_at": "2021-08-10T03:47:17.000000Z"
},
{
"id": 2,
"gallery_name_id": 1,
"title": "Photo 2",
"src": "/storage/photo_gallery_images/pexels-lena-goncharova-8692688-400x300_1628567251.jpg",
"created_at": "2021-08-10T03:47:31.000000Z"
}
]
}
但是,当我提供数据库中不存在的 id 时,它会给我一个“尝试获取非对象的属性 'id'”错误。我找到了一种解决方法,但以一种 hacky 的方式。无论如何,我想知道这个错误的性质或为什么会发生这种情况,因为我找不到我做错了什么。
解决方案
你GalleryNameResource
是这里的问题。
让我们重新格式化您的代码,使其更易于阅读:
public function show($id)
{
$gallery_instance = GalleryName::where('id', $id)->select('id', 'gallery_name','gallery_cover_photo' , 'created_at')->with(['gallery_photos' => function($query) {
return $query->select(['id', 'gallery_name_id', 'photo_title', 'photo_image', 'created_at']);
}])->first();
// $gallery_name == null if id doesn't exist
$gallery_name = new GalleryNameResource($gallery_instance);
// again, if the id doesn't exist, you are passing null to the resource,
// it's like writing new GalleryNameResource(null);
// Remember: $gallery_name, in your code, IS NOT a GalleryName instance.
// It is a GalleryNameResource instance.
// It'll never be null or false, so the next condition is always true.
if($gallery_name){
return response()->json($gallery_name, 200);
}
return response()->json('Gallery Not Found !!', 404);
}
}
当您发送GalleryNameResource
响应时,Laravel 会将其转换为 JSON。
这就是您收到错误的原因:
public function toArray($request)
{
// return parent::toArray($request);
return [
'id' => $this->id,
// 'id' => $this->id, is very likely your error
// Laravel will try to get the id of... null
// $this->id translates to $this->resource->id
// so it translates to $this->null->id
// Trying to get property id.... Error.
'gallery_name' => $this->gallery_name,
'gallery_cover_photo' => $this->gallery_cover_photo,
'created_at' => $this->created_at,
'gallery_photos' => GalleryPhotoResource::collection($this->gallery_photos)
];
}
如何解决您的问题?
public function show($id)
{
$gallery_name = GalleryName::where('id', $id)->select('id', 'gallery_name','gallery_cover_photo' , 'created_at')->with(['gallery_photos' => function($query) {
return $query->select(['id', 'gallery_name_id', 'photo_title', 'photo_image', 'created_at']);
}])->first();
if(!$gallery_name){
return response()->json('Gallery Not Found !!', 404);
}
return response()->json(new GalleryNameResource($gallery_name), 200);
}
}
解决此问题的一种更简洁的方法是使用隐式路由绑定,请在文档中查看:https ://laravel.com/docs/8.x/routing#implicit-binding
推荐阅读
- javascript - 如何仅在特定时间为所有站点设置不缓存,并且始终为特定页面设置不缓存
- java - 由于 kafka 流存储正在等待运行,应用程序无法启动
- spring - 从 java 代码在 xero 中创建联系人会产生错误的请求
- postgresql-12 - 如何在 Ubuntu Desktop 20.04 LTS 上安装 PostGIS
- mysql - 如何在MYSQL数据库中存储列表
- elasticsearch - Elasticsearch 分片和副本搜索性能
- angular9 - 在Angular 9中是否有正确的方法来做routerLink?
- javascript - 如何遍历嵌套的 iframe?
- javascript - 如何同步x轴到窗口的变化
- python - 给定数字中的最大可能数字。(替代),贪心算法