*/ protected $lookupModels = []; /** @var Model */ protected $relation; /** @var string */ protected $polymorphicFieldName; public function __construct(Model $relation, string $polymorphicFieldName) { $this->relation = $relation; $this->polymorphicFieldName = $polymorphicFieldName; } /** * Set the query to look up the given entity type. */ public function forEntity(string $class, array $columns): self { $this->lookupModels[$class] = $columns; return $this; } /** * Set the query to look up all entity types. */ public function forAllEntities(): self { $this->lookupModels[Page::class] = ['id', 'name', 'slug', 'book_id', 'chapter_id', 'text']; $this->lookupModels[Chapter::class] = ['id', 'name', 'slug', 'book_id', 'description']; $this->lookupModels[Book::class] = ['id', 'name', 'slug', 'description', 'image_id']; $this->lookupModels[Bookshelf::class] = ['id', 'name', 'slug', 'description', 'image_id']; return $this; } /** * Build the core query to run. */ protected function build(): Builder { $query = $this->relation->newQuery()->toBase(); $relationTable = $this->relation->getTable(); $modelTables = []; // Load model selects & joins foreach ($this->lookupModels as $lookupModel => $columns) { /** @var Entity $model */ $model = (new $lookupModel); $table = $model->getTable(); $modelTables[] = $table; $query->addSelect($this->tableColumnsToSelectArray($table, $columns)); $query->leftJoin($table, function (JoinClause $join) use ($table, $relationTable, $model) { $polyPrefix = $relationTable . '.' . $this->polymorphicFieldName; $join->on($polyPrefix . '_id', '=', $table . '.id'); $join->where($polyPrefix . '_type', '=', $model->getMorphClass()); $join->whereNull($table . '.deleted_at'); }); } // Where we have a model result $query->where(function (Builder $query) use ($modelTables) { foreach ($modelTables as $table) { $query->orWhereNotNull($table . '.id'); } }); $this->applyPermissionsToQuery($query, 'view'); return $query; } protected function applyPermissionsToQuery(Builder $query, string $action) { $permissions = app()->make(PermissionService::class); $permissions->filterRestrictedEntityRelations( $query, $this->relation->getTable(), $this->polymorphicFieldName . '_id', $this->polymorphicFieldName . '_type', $action, ); } /** * Create an array of select statements from the given table and column. */ protected function tableColumnsToSelectArray(string $table, array $columns): array { $selectArray = []; foreach ($columns as $column) { $selectArray[] = $table . '.' . $column . ' as '. $table . '_' . $column; } return $selectArray; } /** * Get the SQL from the core query being ran. */ public function toSql(): string { return $this->build()->toSql(); } /** * Run the query and get the results. */ public function run(): Collection { return $this->build()->get(); } }