Laravel (nova) 继承映射

Laravel (nova) inheritance mapping

我目前正在构建 laravel nova 应用程序。 我希望能够通过 inheritance mapping.

实现类似于 Doctrine 可以做的事情

让我们假设以下示例:

use Illuminate\Database\Eloquent\Model;


class Event extends Model {
    protected $attributes = [
        'name' => null,
        'starts_at' => null,
        'ends_at' => null,
    ];
}

class EventTypeA extends Event {
  // has extra fields specific to EventTypeA
}

class EventTypeB extends Event {
  // has extra fields specific to EventTypeB
}

现在我希望能够:

  1. 获取所有 EventTypeA
  2. 获取所有 EventTypeB
  3. 获取所有事件,只关心共享信息。

当然,对于上面的列表,过滤、投影等所有 Eloquent 好处都应该适用。


据我所知laravel可能能够正确处理EventTypeAEventTypeB但是Event会必须需要从两个表中获取数据,这实际上是不可能的。

我知道 eloquent 的变形功能,但是根据我的理解,这会导致 Event 核心数据和后代特定属性的单独 nova 视图。这在用户体验方面是不可接受的。

我考虑过为 Event 使用一个接口,然后 EventTypeAEventTypeB 将实现该接口。但是,我认为这将需要大量体力劳动才能让 Eloquent 对事件做一些有意义的事情。

这听起来像是一个常见的问题,但是我无法在 laravel 中找到任何关于如何正确执行此操作的资源(尤其是 nova 可以应对它)。

Laravel 不提供为不同的 table 创建子 类 基础模型的解决方案。反过来也是完全可能的:

class Event extends Model
{
    protected $table = 'events';
}
class EventA extends Event
{
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope(function (Builder $query) {
            $query->where('events.type', '=', 'a');
        });
    }
}

class EventB extends Event
{
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope(function (Builder $query) {
            $query->where('events.type', '=', 'b');
        });
    }
}

我通过为枢轴使用中间模型 table 并将一些属性代理给子模型解决了类似的问题。

那么你的关系就是 BelongsToHasMany

就用户体验而言,您可以通过有条件地检查资源属性来自定义 Nova 中的字段。尽管我建议仅在详细信息和表单视图上执行此操作,因为索引 table 将在返回具有不同列的行时关闭。

public function fields(Request $request)
{
    return array_filter([
        ID::make()->sortable(),

        value(function () {
            if ($this->type === 'a') {
                return Boolean::make('A specific field')->hideFromIndex();
            }
        }),

        value(function () {
            if ($this->type === 'b') {
                return Boolean::make('B specific field')->hideFromIndex();
            }
        }),
    ]);
}

我最近才知道 kirschbaum-development/nova-inline-relationship 这个包允许你将关系内联到 nova 资源中,因此将允许这样的结构:

class Event extends Model
{
  public function eventable()
  {
    return $this->morphTo();
  }
}
class Workshop extends Model
{
  public function event()
  {
    return $this->morphOne(Event::class, 'eventable');
  }
}
class StageTalk extends Model
{
  public function event()
  {
    return $this->morphOne(Event::class, 'eventable');
  }
}

然后在nova资源中

class Workshop extends Resource
{
  public function fields(Request $request)
  {
  return [
    MorphOne::make('Event')->inline(),
  ];
  }
}