《财经》CMS后台查询功能的实现(基于Laravel Repository)

使用 RequestCriteria 统一搜索功能,可自动根据 url 按字段进行搜索,无需写方法

1. 后台搜索框的基本代码:

<div class="panel-group">
    <div class="panel panel-default" style="border: none;">
        <div class="panel-heading">
            <h4 class="panel-title">
                <a data-toggle="collapse" href="#wrapper_search"
                   aria-expanded="false" @if(false == $searchMode)class="collapsed" @endif >
                    搜索相关
                </a>
            </h4>
        </div>
        <div id="wrapper_search" class="panel-collapse collapse @if(true == $searchMode)in @endif"
             aria-expanded="false">
            <div class="panel-body">
                <div class="portlet-heading">
                    <form id="frm_search_info" class="text-dark form-horizontal" action="">
                        <input type="hidden" value=""/>
                        <div class="form-group col-sm-4 pull-left">
                            <label for="order_sn" class="control-label col-sm-4">订单号</label>

                            <div class="col-sm-8">
                                <input type="text" class="form-control" id="title" name="id"
                                       value="{{isset($searchCondition['id'])?$searchCondition['id']:''}}"/>

                            </div>
                        </div>

                        <div class="form-group col-sm-4 pull-left">
                            <label for="snap_goods_name" class="control-label col-sm-4">商品名称</label>

                            <div class="col-sm-8">
                                <input type="text" class="form-control" id="title" name="snap_goods_name"
                                       value="{{isset($searchCondition['snap_goods_name'])?$searchCondition['snap_goods_name']:''}}"/>

                            </div>
                        </div>

                        <div class="form-group col-sm-4 pull-left">
                            <label for="paymentInfo.payment_type" class="control-label col-sm-4">支付方式</label>

                            <div class="col-sm-8">
                                <select class="form-control input-lg select2" id="paymentInfo.payment_type" name="paymentInfo.payment_type"
                                        style="width: 192px;">
                                    <option value="">全部</option>
                                    @if(isset($paymentType))
                                        @foreach($paymentType as $index => $item)
                                            <option value="{{$index}}"
                                                    @if(isset($searchCondition['paymentInfo.payment_type']) && $index == $searchCondition['paymentInfo.payment_type']) selected="selected" @endif>{{$item}}</option>
                                        @endforeach
                                    @endif
                                </select>

                            </div>
                        </div>
                        <div class="form-group col-sm-4 pull-left">
                            <label for="created_at@" class="control-label col-sm-4">至</label>

                            <div class="col-sm-8">
                                <div class="input-group datetimepicker date" id="end_time_picker">
                                    <input class="form-control" id="created_at@"
                                           name="created_at@" type="text"
                                           value="@if(isset($searchCondition['created_at@']) && $searchCondition['created_at@']){{$searchCondition['created_at@']}}@endif">
                                    <span class="input-group-addon" for="created_at@">
                            <span class="glyphicon glyphicon-calendar"></span>
                        </span>
                                </div>

                            </div>
                        </div>

                        <div class="form-group col-sm-4 pull-right">
                            <button type="button" class="btn btn-default m-l-10" id="btn_clear">清空</button>
                            <button type="button" class="btn btn-purple m-l-10" id="btn_export">
                                Excel 导出
                            </button>
                            <button type="button" class="btn btn-primary m-l-10" id="btn_search">搜索</button>

                        </div>

                        <div class="clearfix"></div>

                    </form>
                </div>
            </div>
        </div>
    </div>

</div>

要求表单中的 name 与数据表中的字段名完全一致。
注意:这里是 button,而不是 submit

2. 在YourModelRepositoryEloquent.php (如FlashRepositoryEloquent.php) 中添加 $fieldSearchable 字段

如:

protected $fieldSearchable = [
    'id',
    'snap_goods_name' => 'like',
    'username',
    'order_status',
    'created_at' => ">=",
    'created_at@' => "<=",
    'source_id',
    'paymentInfo.payment_type'
];

注意:

  • 要列出所有需要进行搜索的字段。
  • 等于的可以省略,
  • 模糊搜索用 like,
  • 范围搜索也直接写。
  • 如果一个字段需要用一次以上,需要对 key 进行重写,加一个@

其中,最后一个功能是在 BaseRepositoryEloquent 中定义的。

默认的键值间的分隔符为:, 如http://prettus.local/users?search=name:John Doe;email:john@gmail.com
可以进行自定义。
在 BaseRepositoryEloquent.php 的构造方法中,
$this->keyValueSeparator = '|:'

组件中默认不包含范围选择符,即sql中的between用法。我们进行了改写,以支持该用法。

BaseRepositoryEloquent 中,添加解析搜索url的方法。

public function parserSearchData($searchData)
{
    if (!empty($searchData) && is_array($searchData)) {
        foreach ($searchData as $index => $item) {
            $method = sprintf("parser%s4Search", ucfirst(camel_case(str_replace('@', '', $index))));
            $model = $this->getModel();
            if (method_exists($model, $method)) {
                $searchData[$index] = $model->{$method}($item);
            }
        }
    }

    return $searchData;
}

以及解析原始搜索数据的方法

public function parserOriginSearchData($search)
{
    $searchData = [];
    if (stripos($search, $this->keyValueSeparator)) {
        $fields = explode($this->paramSeparator, $search);

        foreach ($fields as $row) {
            try {
                list($field, $value) = explode($this->keyValueSeparator, $row);
                $searchData[trim($field)] = trim($value);
            } catch (\Exception $e) {
                //Surround offset error
            }
        }
    }
    return $searchData;
}

业务需要,添加了整合后的获取搜索参数的方法

public function getSearchData($param = null, $is_origin = true)
{
    $search = $this->request->get(config('repository.criteria.params.search', 'search'), null);
    $searchData = $this->parserOriginSearchData($search);
    if (false == $is_origin) {
        $searchData = $this->parserSearchData($searchData);
    }
    if (!empty($param)) {
        if (isset($searchData[$param])) {
            $searchData = $searchData[$param];
        } else {
            $searchData = null;
        }
    }
    return $searchData;
}

3. js 文件中添加解析url的方法。

// 搜索 按钮
searchWithParams('/magazine/order?page=1');

function searchWithParams(url) {
    $("#btn_search").click(function () {
        var params = {};
        $("#frm_search_info select, #frm_search_info input[type=text], #frm_search_info input[type=hidden]").each(function () {
            var value = $(this).val();
            if ('' != value) {
                params[$(this).attr('name')] = value;
            }
        });

        if (!$.isEmptyObject(params)) {
            url += "&search=" + parserParams2Url(params);
        }

        location.href = url;
    });

}

该方法实现了对所有输入框、下拉框等搜索框内容的收集并处理,生成一个 Repository 可解析的 url。

4. 回显的数据不需要通过控制器获取后回传,在模板中通过 $searchCondition 全局变量获取即可

如何使用?
控制器中的方法会非常简洁:

public function getIndex(Request $request)
{
    $flashes = $this->repositoryInterface->paginate();

    return View::make("flash/index", array(
        "flashes" => $flashes,
        "flashTypes" => Flash::$flashTypes,
    ));
}

第二部分

上述搜索方法只是实现了单表搜索,如果搜索涉及到跨表该怎么处理?

场景:在模型Order的列表页进行搜索,但搜索的关键字是模型Payment的一个字段,模型Payment有一个指向模型Order的外键 order_id。

实现:

1. 在 app/Models/Order 中,建立与 Payment 模型的关联关系。

/**
 * 支付信息关联关系
 * @return \Illuminate\Database\Eloquent\Relations\HasOne
 */
public function paymentInfo()
{
    return $this->hasOne('App\Models\Payment', 'order_id', 'id');
}

2. Order 的模板文件(列表 resources/views/backend/order/index.blade.php)中,搜索相关部分的 name 和字段名都要加上关联关系的方法前缀。

<div class="form-group col-sm-4 pull-left">
    <label for="paymentInfo.payment_type" class="control-label col-sm-4">支付方式</label>

    <div class="col-sm-8">
        <select class="form-control input-lg select2" id="paymentInfo.payment_type" name="paymentInfo.payment_type"
                style="width: 192px;">
            <option value="">全部</option>
            @if(isset($paymentType))
                @foreach($paymentType as $index => $item)
                    <option value="{{$index}}"
                            @if(isset($searchCondition['paymentInfo.payment_type']) && $index == $searchCondition['paymentInfo.payment_type']) selected="selected" @endif>{{$item}}</option>
                @endforeach
            @endif
        </select>

    </div>
</div>

3. 在YourModelRepositoryEloquent.php (如FlashRepositoryEloquent.php) 中添加 $fieldSearchable 字段

如:

protected $fieldSearchable = [
    'paymentInfo.payment_type'
];

要与模板文件的name一致。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容