laravel 复杂搜索组件

有时候我们希望能和前端好好对接一个页面的功能性展示,如支持的搜索条件有哪些,支持的字段有哪些,复杂搜索

组件代码 ComplexSearch.php

<?php
/**
 * Notes:描述该文件的用途
 * History:文件历史
 * tanyong 2022/5/18
 */

namespace App\components\ComplexSearch;


use App\components\ComplexSearch\Exceptions\ComplexException;
use App\components\ComplexSearch\Exceptions\Ecode;
use App\Models\User;
use Illuminate\Pagination\Paginator;
use Illuminate\Support\Arr;

abstract class ComplexSearch
{
    /**
     * @var null 关联的模型表
     */
    public $eloquentModelTable = null;

    /**
     * @var \Illuminate\Database\Eloquent\Builder
     */
    public $eloquentQuery = null;

    /**
     * @var array 列表标题
     */
    public $headers = [];

    /**
     * @var array 需要隐藏的字段
     */
    protected $hidden = [];

    /**
     * @var array 索引条件
     */
    public $whereConditions = [];

    /**
     * @var array 支持的索引条件
     */
    public $conditions = [];

    /**
     * @var string[] 要查询的字段
     */
    public $selectFields = ['*'];

    /**
     * @var int 目标页数
     */
    public $page = 1;

    /**
     * @var int 每页显示行数
     */
    public $pageSize = 25;

    /**
     * @var array 排序
     */
    public $orderBy = [
        'field' => 'created_at',
        'type' => 'desc'
    ];

    public function __construct()
    {
        //启动组件检查
        $this->startCheck();
    }

    /**
     * Notes:构建搜索条件
     * Author:tanyong
     * DateTime:2022/5/18
     * @param array $params
     */
    public function make($params)
    {
        //获取需要查询的字段
        if (isset($params['fields'])) {
            $this->selectFields = $params['fields'];
        }

        //分页数
        if (isset($params['page']) && $params['page'] >= 1) {
            $this->page = $params['page'];
        }

        //每页显示记录条数
        if (isset($params['pageSize']) && $params['pageSize'] >= 1) {
            $this->pageSize = $params['pageSize'];
        }

        //索引条件
        if (isset($params['params']) && !empty($params['params'])) {
            $keys = array_column($params['params'],0);
            $condtionKeys = array_keys($this->conditions);

            foreach ($keys as $key) {
                if(!in_array($key,$condtionKeys))
                    throw new ComplexException('未知的检索条件:'.$key,Ecode::PARAMS_ERROR);
            }

            $this->whereConditions = $params['params'];
        }

        return $this;
    }

    public function query()
    {
        $query = $this->getEloquentQuery();

        //条件组合
        if (!empty($this->whereConditions)) {
            foreach ($this->whereConditions as $condtion) {
                $key = $condtion[0];
                $type = $condtion[1];
                $value = $condtion[2];
                if(!is_string($key))
                    throw new ComplexException('键名不是字符串',Ecode::PARAMS_ERROR);

                //开始条件组合
                switch ($type) {
                    case 'eq':
                        if(!is_string($value))
                            throw new ComplexException('对应值不是字符串',Ecode::PARAMS_ERROR);
                        $query->where($key, $value);
                        break;
                    case 'select':
                        if(!is_string($value))
                            throw new ComplexException('对应值不是字符串',Ecode::PARAMS_ERROR);
                        $query->where($key, $value);
                        break;
                    case 'section':
                        if(!is_array($value))
                            throw new ComplexException('对应值不是数组',Ecode::PARAMS_ERROR);
                        $query->where([
                            [$key, '>=', $value[0]],
                            [$key, '<=', $value[1]]
                        ]);
                        break;
                    case 'not_eq':
                        if(!is_string($value))
                            throw new ComplexException('对应值不是字符串',Ecode::PARAMS_ERROR);
                        $query->where($key, '!=', $value);
                        break;
                    default:
                        $query->where($key, $value);
                }
            }
        }

        //排序
        $query->orderBy($this->orderBy['field'], $this->orderBy['type']);

        return $this;
    }

    public function get()
    {
        $result = [];

        $this->query();

        $query = $this->getEloquentQuery();

        //字段效验
        $selectFields = $this->checkFields($this->selectFields);

        $pageInfo = $query->paginate($this->pageSize, $selectFields, 'page', $this->page);

        //隐藏目标字段
        if(!empty($pageInfo->items()) && !empty($this->hidden))
        {
            $list = $this->hiddenFields($pageInfo->items());
        }

        $result['pageInfo'] = [
            'current_page'      =>  $pageInfo->currentPage(),
            'first_page_url'    =>  $pageInfo->previousPageUrl(),
            'next_page_url'     =>  $pageInfo->nextPageUrl(),
            'last_page'         =>  $pageInfo->lastPage(),
            'list'              =>  $list
        ];

        $result['conditions'] = $this->conditions;

        $result['headers'] = $this->headers;

        return $result;
    }

    public function checkFields($fields)
    {

        if($fields[0] != '*' && !empty($fields))
        {
            $headerKeys = array_keys($this->headers);

            foreach($headerKeys as $key)
            {
                if(!in_array($key,$fields))
                {
                    array_push($fields,$key);
                }
            }
        }

        return $fields;
    }

    /**
     * @param User [] $data
     */
    public function hiddenFields($data)
    {
        if(!empty($this->hidden) && !empty($data))
        {
            $removeStatus = false;
            $keyColumns = array_keys($data[0]->getOriginal());
            foreach($this->hidden as $field)
            {
                if(in_array($field,$keyColumns))
                {
                    $removeStatus = true;
                    break;
                }
            }

            if($removeStatus)
            {
                $data = array_map(function($item){
                    foreach($this->hidden as $field)
                        if(isset($item[$field]))
                            unset($item[$field]);
                    return $item;
                },$data);
            }
        }

        return $data;
    }

    public function getEloquentModelTable()
    {
        if (empty($this->eloquentModelTable))
            throw new ComplexException('没有指定关联的表', Ecode::ERROR_TABLE);

        return $this->eloquentModelTable;
    }

    /**
     * @return null
     */
    public function getEloquentQuery()
    {
        if (empty($this->eloquentQuery)) {
            $class = $this->getEloquentModelTable();

            $this->eloquentQuery = $class::query();
        }

        return $this->eloquentQuery;
    }

    public function startCheck()
    {
        //效验支持的条件
        if(empty($this->conditions))
            throw new ComplexException('支持的查询条件不可为空',Ecode::IS_EMPTY_CONDITION);

        //效验需要隐藏的字段是否和headers标题头冲突
        if(!empty($this->hidden))
        {
            $headerKeys = array_column($this->headers,'value');

            $intersection = array_intersect($headerKeys,$this->hidden);

            if(!empty($intersection))
                throw new ComplexException('headers表头信息和需要隐藏字段不能存在交集',Ecode::PARAMS_ERROR);
        }
    }
}

继承类实现

<?php
/**
 * Notes:描述该文件的用途
 * History:文件历史
 * tanyong 2022/5/18
 */

namespace App\Services\User\Search;

use App\components\ComplexSearch\ComplexSearch;
use App\Models\User;

class UserComplex extends ComplexSearch
{
    public $eloquentModelTable = User::class;

    //表头信息
    public $headers = [
        ['value' => 'id', 'label' => '用户id'],
        ['value' => 'nickname', 'label' => '昵称'],
        ['value' => 'email', 'label' => '邮箱'],
        ['value' => 'deleted_at', 'label' => '是否删除'],
        ['value' => 'created_at', 'label' => '创建时间']
    ];

    //需要隐藏的字段
    public $hidden = [
        'password','username','email_verified_at'
    ];

    //支持的索引条件
    public $conditions = [
        'id' => [
            'ctype' => 'input',
            'display' => true,
            'operator' => '=',
            'label' => '会员ID',
        ],
        'nickname' => [
            'ctype' => 'input',
            'display' => true,
            'operator' => '=',
            'label' => '用户昵称',
            'custom' => true,
        ],
        'created_at' => [
            'ctype' => 'date-in',
            'display' => true,
            'format' => 'Y-m-d H:i:s',
            'label' => '创建时间',
            'custom' => true
        ],
    ];

    public function query()
    {

        parent::query();
    }

}

如何使用

public function index10()
    {
        $params = [
            'page'      =>  1,
            'pageSize'  =>  10,
            'params'    =>  [
                [
                    'created_at','section',[
                        '2022-05-16 13:55:36','2022-05-17 11:35:40'
                    ]
                ]
            ]
        ];

        $seach = new UserComplex();
        return [
            'code'      =>  0,
            'message'   =>  'success',
            'result'    =>  $seach->make($params)->get()
        ];
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值