Как исправить ошибку "Пожалуйста, используйте whereHasMorph() для отношений MorphTo". при использовании функции поиска Laravel BackPack?

У меня очень простые полиморфные отношения "один ко многим", как показано ниже.

posts
    id - integer
    title - string

videos
    id - integer
    title - string

comments
    id - integer
    body - text
    commentable_id - integer
    commentable_type - string

Ниже показано, как выглядят отношения в моделях:

    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');
        }
    }

Я использую Laravel Backpack CRUD для управления comments, в CommentCrudController::setup() Функция, я добавляю столбцы следующим образом:

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.
    ]);

} 

С вышеуказанной конфигурацией в CommentCrudController::setup() функция, я получаю обзорную таблицу комментариев как обычно. Но когда я пытался найти что-то с помощью формы поиска по рюкзаку, я получил следующую ошибку:

{
  message: "Please use whereHasMorph() for MorphTo relationships."
  trace: [
    {file: vendor/backpack/crud/src/PanelTraits/Search.php", line: 91}
  ]
}

Я понимаю это, потому что это One-To-Many полиморфная связь с morphTo() функция и в CommentCrudController::setup() функция, которую я использовал 'type' => "select" добавить title из "Related Entity" как столбец, при попытке поиска записей Laravel Backpack попытается выполнить следующий запрос внутри trait Search::applySearchLogicForColumn() функция:

    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...
        }

Как говорится в ошибке, $query->orWhereHas() следует изменить на $query->whereHasMorph(), Но изменение этого не решает проблему. И я также хочу иметь возможность искать в title столбец связанной модели.
Как я могу это исправить?

0 ответов

Я нашел решение, переопределив следующие три функции в CommentCrudController:

search()
applySearchTerm($searchTerm)
applySearchLogicForColumn($query, $searchTerm)

в search() функция, я сохранил все, так как это связано с разбивкой на страницы, сортировкой и т. д. Кроме вызова $this->crud->applySearchTerm()функция. Я изменил его на звонок$this->applySearchTerm() который я также переопределил в CommentCrudController.

Поскольку в моем случае эта операция работает с определенными таблицами и столбцами базы данных, я мог переопределить applySearchTerm($searchTerm) функционируют следующим образом:

public function applySearchTerm($searchTerm)
{
    return $this->crud->query->where(function ($query) use ($searchTerm) {
        $this->applySearchLogicForColumn($query, $searchTerm);
    });
}

И решение происходит путем переопределения applySearchLogicForColumn($query, $searchTerm) функционируют следующим образом:

public function applySearchLogicForColumn($query, $searchTerm) 
{
    $query->orWhere('body', 'LIKE', '%' . $searchTerm . '%')
          ->orWhereHasMorph(
              'commentable',
              [
                   Post::class,
                   Video::class,
              ], 
              function (Builder $query) use ($searchTerm) {
                   $query->where('title', 'LIKE', '%' . $searchTerm . '%')
              }
          );
} 

В случае, если у вас есть другая связанная модель морфа с другим именем столбца, чем title например

posts
    id - integer
    title - string

videos
    id - integer
    title - string

users
    id - integer
    full_name - string  // table 'users' with 'full_name' column where you also want to apply search term to.

comments
    id - integer
    body - text
    commentable_id - integer
    commentable_type - string

Вы можете переопределить applySearchLogicForColumn($query, $searchTerm) функционируют следующим образом:

public function applySearchLogicForColumn($query, $searchTerm) 
{
    $query->orWhere('body', 'LIKE', '%' . $searchTerm . '%')
          ->orWhereHasMorph(
              'commentable',
              [
                   Post::class,
                   Video::class,
              ], 
              function (Builder $query) use ($searchTerm) {
                   $query->where('title', 'LIKE', '%' . $searchTerm . '%')
              }
          )
          ->orWhereHasMorph(
              'commentable',
              [
                   User::class,
              ], 
              function (Builder $query) use ($searchTerm) {
                   $query->where('full_name', 'LIKE', '%' . $searchTerm . '%')
              }
          );
} 
Другие вопросы по тегам