简体   繁体   中英

laravel backpack ajax FetchOperation - search by all parents recursively

On my model AdGroup.php I have:

public function parent() {
    return $this->belongsTo(AdGroup::class);
}

public function children() {
    return $this->hasMany(AdGroup::class, 'parent_id');
}

public function getTreeTitleAttribute() {
    $treeTitle = $this->title;
    if($this->parent) {
        $treeTitle = $this->parent->getTreeTitleAttribute() . ' > ' . $treeTitle;
    }
    return $treeTitle;
}

$model->treeTitle returns me a full title of AdGoup, for example: Fruits > Red fruits > Strawberries

On AdGroupCrudController.php I have:

protected function setupCreateOperation()
{
    CRUD::setValidation(AdGroupRequest::class);
    
    $this->crud->addField([
        'label' => __('admin.parent'),
        'type' => 'relationship',
        'name' => 'parent_id',
        'entity' => 'parent',
        'attribute' => 'tree_title',
        'ajax' => true,
        'minimum_input_length' => 0,
        'allows_null' => true
    ]);
}

public function fetchParent()
{
    return $this->fetch([
        'model' => \App\Models\AdGroup::class,
        'query' => function($model) {
            return $model->orderBy('lft')->orderBy('id', 'ASC');
        } 
    ]);
}

This shows me a select2 dropdown with ability to search through all categories and their tree titles are shown. Only one drawback - search doesn't work correctly. It searches by title (database column) and not the treeTitle attribute that I have defined in my model. I understand that this is because fetchParent method searches directly from DB and only then, on returned results I receive my treeTitle, but perhaps this is possible to fix? I found an extended fetch method on Laravel backpack docs:

public function fetchUser() {
        return $this->fetch([
            'model' => User::class,
            'query' => function($model) {
                $search = request()->input('q') ?? false;
                if ($search) {
                    return $model->whereRaw('CONCAT(`first_name`," ",`last_name`) LIKE "%' . $search . '%"');
                }else{
                    return $model;
                }
            },
            'searchable_attributes' => []
        ]);
    }

Perhaps it is possible to extend it to fit my needs? The same issue remains when I search on backpack datatable (list).

Indeed, you've correctly pinpointed the underlying problem:

I understand that this is because fetchParent method searches directly from DB and only then, on returned results I receive my treeTitle;

And the solution: you can use Fetch's query attribute to customize the query, and include your treeTitle. The only problem is... then you'll have to do the tree_title calculation... in SQL. Which won't be easy.


Alternatively, don't use the relationship field and the Fetch operation. Instead, you can use the select2_from_ajax field , which provides more room for customization .

Because you create your own route & CrudController to respond to AJAX requests, in that controller you can

  • manually search for the search term
  • keep only 10 results
  • then do the PHP processing for only those 10 results

The example in the docs will provide a good point to start.

Note that would have one downside: people won't be able to search for Fruits > Red Fruits , they can only search for Fruits or Red Fruits (one at a time) . But that might be a worthy compromise: doing it this way would save you from having to write a pretty complicated SQL query and/or stored function.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM