lckamal - 1 year ago

I would like to search from relationship field in table filters. Is this supported by default? eg. I have a profiles stream which references to users. so I would like to search from users display_name field.

Answer

piterden - 1 year ago

        'user'   => [
            'filter'      => 'search',
            'query'       => RelationFilterQuery::class,
            'fields'      => [
                'username',
                'email',
                'display_name',
                'first_name',
                'last_name',
            ],
            'config' => [
                'placeholder' => 'Search by user data...',
                'prefix'      => 'user_',
            ]
        ],

piterden - 1 year ago

        'user'   => [
            'filter'      => 'search',
            'query'       => RelationFilterQuery::class,
            'fields'      => [
                'username',
                'email',
                'display_name',
                'first_name',
                'last_name',
            ],
            'config' => [
                'placeholder' => 'Search by user data...',
                'prefix'      => 'user_',
            ]
        ],

piterden - 1 year ago

<?php namespace Defr\DefaultModule\Project\Table\Filter;

use Anomaly\Streams\Platform\Ui\Table\Component\Filter\Contract\FilterInterface;
use Anomaly\Streams\Platform\Ui\Table\TableBuilder;
use Illuminate\Contracts\Container\Container;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\Relation;

/**
 * Class RelationFilterQuery
 */
class RelationFilterQuery
{

    /**
     * IoC app
     *
     * @var Container
     */
    protected $container;

    /**
     * Create an instance of RelationFilterQuery class
     *
     * @param Container $container The container
     */
    public function __construct(Container $container)
    {
        $this->container = $container;
    }

    /**
     * Handle the filter.
     *
     * @param Builder         $query
     * @param FilterInterface $filter
     */
    public function handle(
        Builder $query,
        TableBuilder $builder,
        FilterInterface $filter
    )
    {
        $model    = $builder->getTableModel();
        $relation = $model->{$filter->getSlug()}();

        if (!($relation instanceof Relation))
        {
            return;
        }

        $relationTableName = $relation->getRelated()->getTableName();

        $fields = $filter->getFields();

        if (!in_array('id', $fields))
        {
            $fields[] = 'id';
        }

        $columns = $query->getQuery()->columns;

        foreach ($fields as $key)
        {
            $field     = $relationTableName.'_'.$key;
            $columns[] = $relationTableName.'.'.$key.' AS '.$field;
        }

        $query->select($columns);

        $query->leftJoin(
            $relationTableName,
            $relationTableName.'.id',
            '=',
            $model->getTableName().'.'.$relation->getForeignKey()
        );

        foreach ($fields as $key)
        {
            $field = $relationTableName.'.'.$key;

            $query->orWhere($field, 'LIKE', "%{$filter->getValue()}%");
        }
    }
}

ryanthompson - 1 year ago

Similar to what @piterden said but the query would go in a text type filter which is generic. You'd define everything about it and the query class would probably join or something. But yes you can.

That might be a good thing to add to core actually. Make your own for the time being but if you would please add an issue to make this. Ill get it knocked out within a week or two.