我试着到处寻找解决方案,但都失败了。这里是:
我正在为一个网站制作一个图片库模块。我有一个名为"GalleryName"的模型和另一个名为"GalleryPhoto"的模型,并在它们之间建立了一个hasMany关系。
我正在使用Vue JS和我用来显示照片的包,要求我使用单词"title"作为照片名称的键,并使用"src"作为存储文件的完整路径的键。我决定使用资源文件来更改键和值,而不是更改数据库和其他逻辑。
首先,这是我的迁移:
<?php
use IlluminateDatabaseMigrationsMigration;
use IlluminateDatabaseSchemaBlueprint;
use IlluminateSupportFacadesSchema;
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 IlluminateDatabaseMigrationsMigration;
use IlluminateDatabaseSchemaBlueprint;
use IlluminateSupportFacadesSchema;
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 AppModels;
use IlluminateDatabaseEloquentFactoriesHasFactory;
use IlluminateDatabaseEloquentModel;
class GalleryName extends Model
{
use HasFactory;
protected $guarded = [];
public function gallery_photos(){
return $this->hasMany(GalleryPhoto::class);
}
}
// Gallery Photo
<?php
namespace AppModels;
use IlluminateDatabaseEloquentFactoriesHasFactory;
use IlluminateDatabaseEloquentModel;
class GalleryPhoto extends Model
{
use HasFactory;
protected $guarded = [];
public function gallery_name(){
return $this->belongsTo(GalleryName::class);
}
}
以下是我的资源文件:
// Gallery Name Resource
<?php
namespace AppHttpResources;
use IlluminateHttpResourcesJsonJsonResource;
class GalleryNameResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param IlluminateHttpRequest $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 AppHttpResources;
use IlluminateHttpResourcesJsonJsonResource;
class GalleryPhotoResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param IlluminateHttpRequest $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 AppHttpControllers;
use IlluminateHttpRequest;
use AppModelsGalleryName;
use AppHttpResourcesGalleryNameResource;
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'"错误。我找到了一个变通的办法,但用的是一种粗糙的方式。无论如何,我想知道这个错误的性质,或者为什么会发生这种情况,因为我找不到我做错了什么。
你的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