Laravel - 多个表格上的全文搜索

时间:2014-02-19 19:48:56

标签: php mysql laravel laravel-4 eloquent

我正在使用Laravel 4和Eloquent模型进行我们正在开发的项目。 数据库符合3NF,一切都很好。从MySQL版本开始,所有MySQL表都从InnoDB切换回MyISAM。 5.6(InnoDB中的全文搜索仅支持5.6及更高版本。)

在创建一些数据库搜索过滤器时,我发现使用Eloquent模型与查询生成器相比存在一些不足。具体而言,特别是在尝试对多个表中的列进行全文搜索时(并保留在Eloquent的对象上下文中)。

为简单起见,我们有以下数据库结构:

--projects
    --id
    --name
    --status
    --...
--users
    --id
    --...
--roles
    --id
    --project_id
    --user_id
    --...
--notes
    --id
    --project_id
    --user_id
    --note
    --....

以下代码(问题的简化和最小化)目前工作正常,全文搜索仅适用于一个表(projects表)。

if (Request::isMethod('post'))
        {

                $filters = array('type_id','status','division','date_of_activation','date_of_closure');

                foreach ($filters as $filter) {
                    $value = Input::get($filter);
                    if (!empty($value) && $value != -1) {//-1 is the value of 'ALL' option
                        $projects->where($filter,'=',$value);
                    }
                }

                $search = Input::get('search');

                if (!empty($search)) {
                    $projects->whereRAW("MATCH(name,description) AGAINST(? IN BOOLEAN MODE)",array($search));
                }

        }


// more code here...
// some more filters...
// and at the end I am committing the search by using paginate(10)

return View::make('pages/projects/listView',
            array(
            "projects" => $projects->paginate(10)
            )
        );

我需要扩展全文搜索以包含以下列:projects.nameprojects.descriptionnotes.note。 在试图找到如何使用Eloquent时,我们继续回到查询生成器并运行自定义查询,这将工作正常,但我们将面临这些问题/缺点:

  1. 当Eloquent返回模型对象时,Query Builder返回一个数组。由于我们正在扩展每个模型以包含方法,我们真的不想放弃Eloquent模型的真棒。我们真的不想在返回结果上使用Eloquent Project::find($id)来重新获得对象。
  2. 我们正在链接“where”方法以获得任意数量的过滤器 分配给它以及代码可重用性。好像混合 Eloquent和Query Builder声明将共同打破我们的链接。
  3. 为了这个项目的一致性,我们希望所有的数据库查询 留在Eloquent的内涵。
  4. 阅读Laravel的文档和API,我找不到使用Eloquent运行原始SQL查询的方法。有whereRAW(),但不够广泛。我认为这是设计所造成的限制,但它仍然是一种限制。

    所以我的问题是:

    1. 是否可以在多个表的列上运行全文搜索,仅在Eloquent中。我在网上看到的每一条信息都是使用Query Builder提到的。
    2. 如果没有,是否可以使用查询生成器搜索并返回Eloquent对象? (无需在数组结果上运行Project::find($id)。)
    3. 最后,是否可以将Eloquent和Query Builder where方法链接在一起,而仅在稍后使用get()paginate(10)提交。
    4. 据我所知,Eloquent和Query Builder是不同的生物。但是如果混合两者都可以,或者使用Eloquent来运行原始SQL查询,我相信Eloquent模型将变得更加健壮。在我看来,仅使用查询生成器有点像使用Laravel框架。

      希望得到一些有关这方面的见解,因为Laravel的论坛/社区似乎仍在不断发展,尽管我发现它是一个了不起的框架!

      谢谢,感谢您提出的任何意见:)

2 个答案:

答案 0 :(得分:4)

首先,您可以在模型中使用查询范围

public function scopeSearch($query, $q) 
{        
   $match = "MATCH(`name`, `description`) AGAINST (?)";
   return $query->whereRaw($match, array($q))
                ->orderByRaw($match.' DESC', array($q));  
}

通过这种方式,您可以获得“eloquent collection”作为回报

$projects = Project::search(Input::get('search'))->get();

然后,要搜索笔记,你可以制作一个更复杂的范围,加入笔记并在那里搜索。

答案 1 :(得分:1)

不确定这是否有帮助,但innoDB中有一种解决方法(在支持全文搜索的版本中),也许它适用于你。
让我们使用'笔记'作为第二个表格

SELECT MATCH(name,description) AGAINST(? IN BOOLEAN MODE),
       MATCH(notes.note) AGAINST(? IN BOOLEAN MODE)
FROM ...

WHERE
MATCH(name,description) AGAINST(?) OR
MATCH(notes.note) AGAINST(?)