Closed thisisablock closed 4 years ago
I plan to release https://github.com/TitasGailius/nova-search-relations/pull/27 soon.
Then a "morph" relation search could simply be something like a custom MorphSearch
class.
/**
* Get the searchable columns for the resource.
*
* @return array
*/
public static function searchableRelations(): array
{
return [
'commentable' => new MorphSearch(['title', 'name']),
];
}
Another thing I don't necessarily agree with is that you pull all types from the database.
It would fail if we had a commentable
relationship that could either be a Post
or a Video
and one of those model tables didn't have some of the specified columns:
/**
* The relationship columns that should be searched.
*
* @var array
*/
public static $searchRelations = [
'commentable' => ['post_title', 'video_description'],
];
That's why an approach similar to this might be better:
/**
* Get the searchable columns for the resource.
*
* @return array
*/
public static function searchableRelations(): array
{
return [
'commentable' => new MorphSearch([
'App\\Models\\Post' => ['psot_title'],
'App\\Models\\Video' => ['video_description'],
]),
];
}
I merged #27. Now you have full control on how the search works and you may even extend the search capabilities with your own logic.
Regarding morphable search, I'll check it this/next week.
@TitasGailius thanks :)
@TitasGailius thanks for adding this feature!
One issue I'm running into while using the master branch after this feature has been added is that ensureRelationshipExists
in RelationSearch
always fails on nested relationships when applying the search.
I'm unfortunately not sure why though.. the same queries work just fine on the tagged version 1.0.6 (nested relations also work fine after removing the ensureRelationshipExists check)
@TitasGailius What if I have a nester relation? Let's say I have something like:
commentable(Video or Photo).someModel
And I want to search fields in from someModel
?
@TitasGailius What if I have a nester relation? Let's say I have something like:
commentable(Video or Photo).someModel
And I want to search fields in from
someModel
?
example
Action Resource
public static function searchableRelations(): array
{
return [
'target' => new MorphSearch([
'App\Models\Role' => ['name'],
'App\Models\User' => [
'name',
'username',
'email',
'roles' => ['name']
],
'App\Models\Permission' => ['name'],
'App\Models\Invite' => [
'email',
'role' => ['name']
],
])
];
}
MorphSearch class
class MorphSearch implements Search
{
/**
* Searchable columns.
*
* @var array
*/
protected $morphRelation;
protected $fallbackClass = '*';
protected $fallbackColumns = [
'id'
];
/**
* Instantiate a new search query instance.
*
* @param array $columns
*/
public function __construct(array $morphRelation)
{
$this->morphRelation = $morphRelation;
}
public function apply(Builder $query, string $relation, string $search): Builder
{
foreach ($this->morphRelation as $morphClass => $columns) {
if (class_exists($morphClass) && is_subclass_of($morphClass, Model::class)) {
$query->orWhereHasMorph($relation, [$morphClass], function ($query) use ($columns, $relation, $search) {
[$columnSearch, $relationSearch] = $this->parseColumns($columns);
(new ColumnSearch($columnSearch->toArray()))->apply($query, $relation, $search);
foreach ($relationSearch as $relationName => $relationsColumns) {
(new RelationSearch($relationsColumns))->apply($query, $relationName, $search);
}
});
}
}
// search all morph class with default columns
$query->orWhereHasMorph($relation, $this->fallbackClass, function ($query) use ($relation, $search) {
return (new ColumnSearch($this->fallbackColumns))->apply($query, $relation, $search);
});
return $query;
}
private function parseColumns($columns): array
{
$columns = collect($columns);
$columnSearch = $columns->filter(function ($value, $key) {
return is_numeric($key);
});
$relationSearch = $columns->filter(function ($value, $key) {
return is_string($key);
});
return [$columnSearch, $relationSearch];
}
}
Good work! It looks really promising, I'll check it later this week.