4000-520-616
欢迎来到免疫在线!(蚂蚁淘生物旗下平台)  请登录 |  免费注册 |  询价篮
主营:原厂直采,平行进口,授权代理(蚂蚁淘为您服务)
咨询热线电话
4000-520-616
当前位置: 首页 > 新闻动态 >
新闻详情
让Laravel 优雅地创建 MySQL 全文索引 | Laravel China 社区
来自 : learnku.com/laravel/t/3600/let 发布时间:2021-03-25

最近在浏览社区话题的时候,看到了一位同仁发表的一篇教程:Laravel 5.3 下通过 migrate 添加 “全文索引” 的方法,突然想到自己之前也研究过这一话题,所以今天就和大家分享一下我的实现思路:如何更优雅地创建fulltext索引。

我非常喜欢Laravel框架的原因之一就是它的拓展性简直太赞了,所有框架本身未实现的功能你都可以自定义实现,而且可以实现得非常优雅。

其实,要想让添加全文索引这个动作变得更“优雅”一点,不外乎为Blueprint类添加一个fulltext方法,操作起来就像这样$table- fulltext(\'column\');,这就与我们平时为字段添加unique索引一样方便了。我们先来看看预想效果:

/** * Run the migrations. * @return voidpublic function up() Schema::table(\'posts\', function (Blueprint $table) { $table- fulltext([\'title\', \'content\']); * Reverse the migrations. * @return voidpublic function down() Schema::dropFulltext([\'title\', \'content\']);}
Step 1 拓展Blueprint类

为了实现上述所预想的效果,显然我们要对Laravel的Illuminate\\Database\\Schema\\Blueprint类进行拓展。这里所说的拓展,实际就是在继承原Blueprint的前提下定义一个新的Blueprint,并且在新的Blueprint类里面添加我们想要拓展的fulltext方法:

 ?phpnamespace Vendor\\Package;use Illuminate\\Database\\Schema\\Blueprint as BaseBlueprint;class Blueprint extends BaseBlueprint * Specify a fulltext index for the table. * @param string|array $columns * @param string $name * @return \\Illuminate\\Support\\Fluent public function fulltext($columns, $name = null) return $this- indexCommand(\'fulltext\', $columns, $name); * Indicate that the given fulltext key should be dropped. * @param string|array $index * @return \\Illuminate\\Support\\Fluent public function dropFulltext($index) return $this- dropIndexCommand(\'dropFulltext\', \'fulltext\', $index);}
Step 2 拓展MySqlGrammar类

光实现一个拓展好的Blueprint肯定还不行,我们追踪一下Laravel的源码就能知道,它的底层是通过Illuminate\\Database\\Schema\\Grammars\\Grammar来编译SQL语法的,相应地MySQL的语法编译则由Illuminate\\Database\\Schema\\Grammars\\MySqlGrammar完成,因此我们还需要拓展一下MySqlGrammar,否则系统就会因为找不到编译fulltext索引的方法,而导致创建索引不成功。拓展MySqlGrammar时我们需要添加两个新的方法compileFulltext和compileDropFulltext,分别用于创建与删除全文索引,参考以下代码:

 ?phpnamespace Vendor\\Package;use Illuminate\\Support\\Fluent;use Illuminate\\Database\\Schema\\Grammars\\MySqlGrammar as BaseMySqlGrammar;class MySqlGrammar extends BaseMySqlGrammar * Compile a fulltext key command. * @param \\Vendor\\Package\\Blueprint $blueprint * @param \\Illuminate\\Support\\Fluent $command * @return string public function compileFulltext(Blueprint $blueprint, Fluent $command) return $this- compileKey($blueprint, $command, \'fulltext\'); * Compile a drop unique key command. * @param \\Vendor\\Package\\Blueprint $blueprint * @param \\Illuminate\\Support\\Fluent $command * @return string public function compileDropFulltext(Blueprint $blueprint, Fluent $command) $table = $this- wrapTable($blueprint); $index = $this- wrap($command- index); return \"alter table {$table} drop index {$index}\";}
Step 3 注入新的MySqlGrammar

实现了以上两个拓展,我们的准备工作就已完毕,接下来就要将这两个拓展好的类注入到系统当中去。究竟如何注入。首先我们要来认识一下Illuminate\\Support\\Facades\\Schema:

 ?phpnamespace Illuminate\\Support\\Facades; * @see \\Illuminate\\Database\\Schema\\Builderclass Schema extends Facade * Get a schema builder instance for a connection. * @param string $name * @return \\Illuminate\\Database\\Schema\\Builder public static function connection($name) return static::$app[\'db\']- connection($name)- getSchemaBuilder(); * Get a schema builder instance for the default connection. * @return \\Illuminate\\Database\\Schema\\Builder protected static function getFacadeAccessor() return static::$app[\'db\']- connection()- getSchemaBuilder();}

不难看出,这个Facade实际上返回由数据库连接的getSchemaBuilder方法生成的Illuminate\\Database\\Schema\\Builder实例,我们继续追踪Illuminate\\Database\\Connection类,找到getSchemaBuilder方法:

/** * Get a schema builder instance for the connection. * @return \\Illuminate\\Database\\Schema\\Builderpublic function getSchemaBuilder() if (is_null($this- schemaGrammar)) { $this- useDefaultSchemaGrammar(); return new SchemaBuilder($this);}

可以看出,我们应该在Laravel实例化SchemaBuilder之前注入拓展好的MySqlGrammar,而伟大的作者早已为我们准备好了接入方法setSchemaGrammar,因此我们只要这样操作就能轻松地完成注入:

use Vendor\\Package\\MySqlGrammar;app(\'db\')- connection()- setSchemaGrammar(new MySqlGrammar);
Step 4 注入新的Blueprint

现在只剩Blueprint还没被注入了,继续追踪\\Illuminate\\Database\\Schema\\Builder,通读一遍源代码,我们可以发现,我们平时写migration文件时所用的table()、create()、drop()等方法都会调用同一个方法createBlueprint:

/** * Create a new command set with a Closure. * @param string $table * @param \\Closure|null $callback * @return \\Illuminate\\Database\\Schema\\Blueprintprotected function createBlueprint($table, Closure $callback = null) if (isset($this- resolver)) { return call_user_func($this- resolver, $table, $callback); return new Blueprint($table, $callback);}

它会先判断是否存在自定义的resolver,而伟大的作者也为我们提供了接入方法blueprintResolver,所以我们可以这样注入拓展好的Blueprint:

use Vendor\\Package\\Blueprint;app(\'db\')- connection()- getSchemaBuilder()- blueprintResolver(function ($table, $callback) { return new Blueprint($table, $callback);});

至此,我们应该可以结束工作了,但事实不是这样的,如果你按照以下的方式来组织你的代码,你会发现,它并不能得到你预想的结果:

 ?phpuse Vendor\\Package\\Blueprint;use Vendor\\Package\\MySqlGrammar;use Illuminate\\Support\\Facades\\Schema;use Illuminate\\Database\\Migrations\\Migration;class CreatePostsTable extends Migration * Run the migrations. * @return void public function up() app(\'db\')- connection()- setSchemaGrammar(new MySqlGrammar); app(\'db\')- connection()- getSchemaBuilder()- blueprintResolver(new Blueprint); Schema::table(\'posts\', function (Blueprint $table) { $table- fulltext([\'title\', \'content\']); * Reverse the migrations. * @return void public function down() app(\'db\')- connection()- setSchemaGrammar(new MySqlGrammar); app(\'db\')- connection()- getSchemaBuilder()- blueprintResolver(new Blueprint); Schema::dropFulltext([\'title\', \'content\']);}

具体原因是什么呢?这里保留一点想象空间,让大家自己去探寻一下结果,有想法的可以一起在回复区讨论。

Step 5 实现新的Schema Facade

这里我提供了一种解决方案,就是另行实现一个Facade:

 ?phpnamespace Vendor\\Package;use Illuminate\\Support\\Facades\\Facade;class Schema extends Facade * Get a schema builder instance for the default connection. * @return \\Illuminate\\Database\\Schema\\Builder protected static function getFacadeAccessor() $connection = static::$app[\'db\']- connection(); $connection- setSchemaGrammar(new MySqlGrammar); $schema = $connection- getSchemaBuilder(); $schema- blueprintResolver(function ($table, $callback) { return new Blueprint($table, $callback); return $schema;}

这样,我们就可以优雅地添加fulltext索引了:

 ?phpuse Vendor\\Package\\Blueprint;use Vendor\\Package\\Schema;use Illuminate\\Database\\Migrations\\Migration;class CreatePostsTable extends Migration * Run the migrations. * @return void public function up() Schema::create(\'posts\', function (Blueprint $table) { $table- fulltext([\'title\', \'content\']); * Reverse the migrations. * @return void public function down() Schema::dropFulltext([\'title\', \'content\']);}
整理好的拓展包

这是我个人整理的一个Package,有需求的可以直接使用,感兴趣的读者也可以下载源码继续研究:mysql-fulltext-laravel。

这篇文章我们并不关注MySQL全文索引对中文的支持,所以请读者选对你的应用场景。其实正如@wyg27 所写教程呈现的,一行代码就能解决的问题,为什么还要如此大费周章?仁者见仁,或许你能从这里学会如何按需拓展你的Laravel应用。这篇帖子没有半点反驳@wyg27 的意思,他的方法已然是最快速有效的了,我只是在此和大家分享一种新思路而已,所以不喜勿喷,2333333

本文链接: http://grammschems.immuno-online.com/view-720460.html

发布于 : 2021-03-25 阅读(0)
公司介绍
品牌分类
其他
联络我们
服务热线:4000-520-616
(限工作日9:00-18:00)
QQ :1570468124
手机:18915418616
官网:http://