I have a very simple One-to-Many polymorphic relationship as following.
posts
id - integer
title - string
videos
id - integer
title - string
comments
id - integer
body - text
commentable_id - integer
commentable_type - string
Below is how the relationship in the models looks like:
class Comment extends Model
{
public function commentable()
{
return $this->morphTo();
}
}
class Post extends Model
{
public function comments()
{
return $this->morphMany('App\Comment', 'commentable');
}
}
class Video extends Model
{
public function comments()
{
return $this->morphMany('App\Comment', 'commentable');
}
}
I use Laravel Backpack CRUD to manage comments
. In the CommentCrudController::setup()
function, I add columns as following:
public function setup() {
// Standard CrudPanel Basic Information goes here...
$this->crud->addColumn([
'name' => 'body',
'label' => 'Comment',
]);
$this->crud->addColumn([
'label' => "Related Entity",
'type' => "select", // Need to use type 'select' for property of related model.
'name' => 'commentable_id ',
'entity' => 'commentable', // Function name, defining the polymorphic relationship.
'attribute' => "title", // The column name of the related database table.
]);
}
With above configuration in the CommentCrudController::setup()
function, I get a comments overview table as normal. But when I tried to search for something using Backpack search form, I've got the following error:
{
message: "Please use whereHasMorph() for MorphTo relationships."
trace: [
{file: vendor/backpack/crud/src/PanelTraits/Search.php", line: 91}
]
}
I do understand that because it is a One-To-Many
polymorphic relation with morphTo()
function and in the CommentCrudController::setup()
function I used 'type' => "select"
to add the title
of the "Related Entity"
as column, when trying to search for records Laravel Backpack
will try to execute the following query inside the trait Search::applySearchLogicForColumn()
function:
if ($column['tableColumn']) {
switch ($columnType) {
// Skipped other cases here...
case 'select':
case 'select_multiple':
$query->orWhereHas($column['entity'], function ($q) use ($column, $searchTerm) {
$q->where($column['attribute'], 'like', '%'.$searchTerm.'%');
});
break;
// Skipped default case here...
}
As the error said, $query->orWhereHas()
should be changed to $query->whereHasMorph()
. But changing this does not solve the problem. And I also want to be able to search in the title
column of the related model.
How can I fix this?
I have found solution by overriding the following three functions in the
CommentCrudController
:In the
search()
function, I preserved everthing, since it has things to do with pagination, sorting etc. Except calling$this->crud->applySearchTerm()
function. I changed it to call$this->applySearchTerm()
which I also overrided in theCommentCrudController
.Because in my use case, this operation works with specific database tables and columns, I could override the
applySearchTerm($searchTerm)
function as following:And the solution happens by overriding the
applySearchLogicForColumn($query, $searchTerm)
function as following:In case, you have another associated morph model with a different column name than
title
e.g.You can override the
applySearchLogicForColumn($query, $searchTerm)
function as following: