我有这段代码
//ImageableTrait
trait ImageableTrait
{
public function images()
{
return $this->morphMany(Image::class, 'imageable')
->orderBy('order', 'ASC');
}
}
//User
class User extend Model
{
use ImageableTrait;
}
//Post
class Post extend Model
{
use ImageableTrait;
}
class ImageCollection extends Collection
{
public function firstOrDefault()
{
if ($this->count() === 0) {
$image = new Image();
$image->id = 'default';
$image->imageable_type = '/* I need the parent className here */';
$image->imageable_id = '.';
}
return $this->first();
}
}
//Image
class Image extend Model
{
public function imageable
{
return $this->morphTo();
}
public function newCollection(array $models = [])
{
return new ImageCollection($models);
}
public function path($size)
{
//Here, there is some logic to build the image path and it needs
//the imageable_type attribute no matter if there is
//an image record in the database or not
return;
}
}
我希望能够这样做
$path = User::find($id)->images->firstOrDefault()->path('large');
但是我无法弄清楚如何让父类名正确地构建路径......
我尝试使用$ morphClass或getMorphClass(),但无法弄清楚如何正确使用它,或者它是否是正确的方法。
对此有何看法?
答案 0 :(得分:1)
我认为你可以保持简单并删除ImageCollection类,因为已经有firstOrNew
方法似乎是你正在寻找的方法。
firstOrNew
方法接受您要匹配的属性数组。如果您不关心属性,则可以传递一个空数组。如果数据库中没有匹配项,它将使用正确的父类型创建一个新实例。
$path = User::find($id)->images()->firstOrNew([])->path('large');
注意:我调用images()
方法来获取MorphMany
对象,以便我可以调用firstOrNew
方法。换句话说,您需要添加括号。否则,您会收到Collection
。
编辑:如果你想通过自动设置一些默认属性来简化一些事情,你可以将它添加到你的ImageableTrait:
public function imagesOrDefault()
{
$defaultAttributes = ['id' => 'default'];
return $this->images()->firstOrNew($defaultAttributes);
}
然后,您可以执行以下操作:$path = User::find($id)->imagesOrDefault()->path('large');
请注意,您的默认属性必须是可填写的才能使其生效。此外,imageable_id和imageable_type将自动设置为您父母的ID和类型。
如果你想将imageable_id的默认值设置为一个句点而不是父的id,那么你必须稍微改一下它,它看起来很像你的原始代码,除非它会进入你的ImageableTrait。
public function imagesOrDefault()
{
// First only gets one image.
// If you want to get all images, then change it to get.
// But if you do that, change the conditional check to a count.
$image = $this->images()->first();
if (is_null($image))
{
$image = new Image();
$image->id = 'default';
$image->imageable_type = $this->getMorphClass();
$image->imageable_id = '.';
}
return $image;
}
答案 1 :(得分:0)
好的家伙我发现现在看起来效果很好的东西,所以我会坚持下去。
在图像模型中,我在制作新集合时添加了一些代码:
public function newCollection(array $models = [])
{
$morphClass = '';
$parent = debug_backtrace(false, 2)[1];
if (isset($parent['function']) AND $parent['function'] === 'initRelation') {
if (isset($parent['args'][0][0])) {
$morphClass = get_class($parent['args'][0][0]);
}
}
return new ImageCollection($models, $morphClass);
}
然后,我只需通过ImageCollection
的构造函数检索morphClassprivate $morphClass;
public function __construct($items = [], $morphClass)
{
parent::__construct($items);
$this->morphClass = $morphClass;
}
public function firstOrDefault()
{
if ($this->count() === 0) {
$image = new Image();
$image->id = 'default';
$image->imageable_type = $this->morphClass;
$image->imageable_id = '.';
}
return $this->first();
}
这样,我可以简单地调用这个方法
User::with('images')->get()->images->firstOrDefault()
在许多情况下,这似乎工作得非常好,如果我有时会遇到一些问题,我会更新这篇文章。