欢迎各位兄弟 发布技术文章
这里的技术是共享的
源代码名称:eloquent-sluggable
Git URL:
git://www.github.com/cviebrock/eloquent-sluggable.git
Git Clone代码到本地:
git clone http://www.github.com/cviebrock/eloquent-sluggable
Subversion代码到本地:
$ svn co --depth empty http://www.github.com/cviebrock/eloquent-sluggable
Checked out revision 1.
$ cd repo
$ svn up trunk
轻松创建 slugs,使你在 Laravel 中的模型更加清晰。
英镑注释:这些说明用于 Laravel 5.5. 如果你使用的是 Laravel,请查看以前版本的文档文档 。
斜线是字符串的简化版本,通常是url友好的。 字符串通常包含将它的转换为一个事例,并删除任何字符( 空格,重音字母,符号,等等 ) 。 结果字符串随后可以用作特定资源的标识符。
例如如果你有一个带有帖子的博客,你可以通过ID引用每个帖子:
http://example.com/post/1
http://example.com/post/2
。但这并不是特别友好的( 尤其是对于搜索引擎优化。) 。
http://example.com/post/My+Dinner+With+Andr%C3%A9+&+Fran%C3%A7ois
解决方法是为标题创建一个slug并使用它。 你可能希望使用内置的Laravel Str::slug()
方法来将该标题转换为更友好的内容:
http://example.com/post/my-dinner-with-andre-francois
这样一个URL会使用户更高兴的( 它可以读,易于输入,等等 ) 。
有关更多信息,你可能希望阅读关于维基百科上的this的说明。
slugs 也是独一无二的。 所以,如果你写另一个标题的文章,你会想要区分它们,通常用增量计数器添加到
http://example.com/post/my-dinner-with-andre-francois
http://example.com/post/my-dinner-with-andre-francois-1
http://example.com/post/my-dinner-with-andre-francois-2
这将使url保持唯一。
针对 5的 eloquent sluggable包旨在自动为你处理所有这一切,并且配置最小。
英镑注释:根据你的Laravel 版本,应该安装不同版本的软件包:
Laravel 版本软件包版本5.5 | 4.3 。* |
5.4 | 4.2.* |
早期版本的Laravel 可以使用包的旧版本,尽管不再支持或者维护这些版本。 请参见 CHANGELOG.md 和 UPGRADING.md 。
通过Composer安装软件包:
$ composer require cviebrock/eloquent-sluggable:^4.3
软件包将自动使用 Laravel 5.5自动 register 。
如果要更改任何默认值,可以选择发布配置文件:
php artisan vendor:publish --provider="CviebrockEloquentSluggableServiceProvider"
你的模型应该使用Sluggable特性,它具有一个抽象方法 sluggable()
,你需要定义。 在这里设置任何模型特定配置( 有关详细信息,请参见下面的配置 ):
useCviebrockEloquentSluggableSluggable;classPostextendsModel{useSluggable;/** * Return the sluggable configuration array for this model. * * @return array*/publicfunctionsluggable() {return ['slug'=> ['source'=>'title' ] ]; }}
当然,模型和数据库需要一列来存储 slug 。 可以使用 slug
或者任何其他适当的NAME ;配置 array 将确定数据将存储到哪个字段。 你将需要通过你自己的迁移手动添加该列。
就是这样。你的模型是"sluggable" !
保存模型很简单:
$post=newPost(['title'=>'My Awesome Blog Post',]);$post->save();
所以检索一下塞子
echo$post->slug;
还要注意,如果使用 replicate()
方法复制模型,包会自动重新打印模型,以确保唯一性。
$post=newPost(['title'=>'My Awesome Blog Post',]);$post->save();// $post->slug is"my-awesome-blog-post"$newPost=$post->replicate();// $newPost->slug is"my-awesome-blog-post-1"
注意空字符串,非字符串或者其他"奇数"源值将导致不同的slugs:
产生的源值 Slug字符串 | 字符串 |
(空字符串) | 否则,不会设置任何蛞蝓。 |
null | 否则,不会设置任何蛞蝓。 |
0 | "0" |
1 | "1" |
false | "0" |
true | "1" |
( 上述值将受到任何唯一或者其他检查的影响。)
生成 slugs的所有逻辑都由 CviebrockEloquentSluggableServicesSlugService
类。
一般来说,不需要直接访问这里类,尽管有一个 static 方法可以用于生成一个给定字符串。
useCviebrockEloquentSluggableServicesSlugService;$slug=SlugService::createSlug(Post::class, 'slug', 'My First Post');
对于那些希望在实际创建模型之前,你希望向用户展示独特的slug插件的ajax y 控制器或者类似的内容来说,这将是非常有用的。 方法的前两个参数是模型和被测试的蛞蝓字段,第三个参数是用于测试插入函数的源字符串。
你还可以将配置值的可选 array 作为第四个参数传递。 这将优先于正被测试的蛞蝓场的正常配置值。 如果将模型配置为使用唯一的slugs,但由于某些原因而希望生成slug版本,则可以:
$slug=SlugService::createSlug(Post::class, 'slug', 'My First Post', ['unique'=>false]);
注意:事件应该工作,但是还没有完全测试。 请帮我 !
Sluggable模型将激发两个有说服力的模型事件: ""还有"slugged"。
"slugging"事件是在生成蛞蝓之前激发的。 如果此事件的回调返回 false,则不执行 slugging 。
"slugged"事件是在生成一个鼻涕虫之后激发的。 在模型不需要 slugging ( 由 needsSlugging()
方法确定)的情况下,不会调用它。
你可以与任何其他Eloquent的模型事件一样钩子到这些事件中:
Post::registerModelEvent('slugging', function($post) {if ($post->someCondition()) {// the model won't be sluggedreturnfalse; }});Post::registerModelEvent('slugged', function($post) {Log::info('Post slugged: '.$post->getSlug());});
配置的目的是尽可能灵活。 你可以为所有的Eloquent模型设置默认值,然后为单个模型覆盖这些设置。
默认情况下,全局配置在 app/config/sluggable.php
文件中设置。 如果未设置配置,则使用包默认值。 下面是一个配置示例,其中显示了所有默认设置:
return ['source'=>null,'maxLength'=>null,'maxLengthKeepWords'=>true,'method'=>null,'separator'=>'-','unique'=>true,'uniqueSuffix'=>null,'includeTrashed'=>false,'reserved'=>null,'onUpdate'=>false,];
对于单个模型,配置是在 sluggable()
方法中处理的,你需要实现。 方法应当返回索引 array,其中键表示存储蛞蝓值的字段,值是该字段的配置。 这意味着可以基于不同的源字符串和不同的配置选项为相同的模型创建多个 slugs 。
publicfunctionsluggable(){return ['title-slug'=> ['source'=>'title' ],'author-slug'=> ['source'=> ['author.lastname', 'author.firstname'],'separator'=>'_' ], ];}
这是字段的字段或者 array,用于构造 slug 。 每个 $model->field
都连接( 空间分离) 以构建sluggable字符串。 这些属性可以是模型属性( 例如 。 数据库中的字段),关系属性或者自定义的getter 。
若要引用相关模型中的字段,请使用点表示法。 例如,下列书的塞子将由它的作者的NAME 和书籍标题生成:
classBookextendsEloquent{useSluggable;protected$fillable= ['title'];publicfunctionsluggable() {return ['slug'=> ['source'=> ['author.name', 'title'] ] ]; }publicfunctionauthor() {return$this->belongsTo(Author::class); }}...classAuthorextendsEloquent{protected$fillable= ['name'];}
使用自定义获取器的示例:
classPersonextendsEloquent{useSluggable;publicfunctionsluggable() {return ['slug'=> ['source'=>'fullname' ] ]; }publicfunctiongetFullnameAttribute() {return$this->firstname.''.$this->lastname; }}
如果 source
为空,false 或者 null,则 $model->__toString()
的值将用作slug生成的源。
将这个设置为正整数将确保你生成的slugs 限制在最大长度( 比如 ) 。 确保它们适合你的数据库字段:。 默认情况下,这里值为空,并且不执行任何限制。
注意:如果启用了 unique
,并且预期有几个具有相同蛞蝓的模型,那么应该把这个值设置为小于数据库字段长度的几个字符。 为了保持唯一性,为了保持唯一性,该类将为后续模型追加" -1"。" -2"。" -3"。等等 。 这些增量扩展不包括在 maxLength
计算的一部分。
如果你使用 maxLength
设置截断了 slugs,那么你可以能想要确保在单词中间不会截断 slugs 。 例如如果源字符串是"我的第一个帖子",而 maxLength
是 10,生成的蛞蝓将最终是"my-first-p",这是不理想的。
默认情况下,maxLengthKeepWords
值被设置为 true,这将修剪部分词尾,从而导致"我的第一个"而不是"my-first-p"。
如果要保留部分单词,则将这里配置设置为 false 。
定义用于将sluggable字符串转换为slug的方法。 这里配置有三种可能的选项:
当 method
为空时,包使用默认的slug引擎 -- cocur/slugify --来创建 slug 。
如果 method
是可以调用的,则使用该函数或者类方法。 函数/方法应为两个参数: 要处理的字符串和分隔符字符串。 例如要使用 Laravel的Str::slug
,你可以执行以下操作:
'method'=> ['IlluminateSupportStr', 'slug'],
你也可以将 method
定义为关闭( 同样,需要两个参数):
'method'=>function ($string, $separator) {returnstrtolower(preg_replace('/[^a-z]+/i', $separator, $string));},
任何 method
的其他值都将引发异常。
有关更复杂的引线要求,请参见下面的扩展 Sluggable 。
默认情况下,更新模型不会尝试并生成新的slug值。 假设一旦生成了你的,你就不会想要它改变( 如果你使用的是 true的slugs,并不希望混乱你的SEO磁盘,这可以能特别是。) 。
如果你想重新生成一个或者多个模型字段,则可以在更新之前将这些字段设置为空或者空字符串:
$post->slug=null;$post->update(['title'=>'My New Title']);
如果这是你每次更新模型所需的行为,那么将 onUpdate
选项设置为 true 。
定义在构建蛞蝓时使用的分隔符,并将它的传递给上面定义的method
。 默认值是连字符。
这是定义 slugs 是否应该在给定类型的所有模型中唯一的布尔值。 例如如果你有两篇博文,两个都叫"我的博客帖子",那么如果 unique
是 false,那么它们都会把。 这可以能是个问题,比如 如果你在url中使用了。
通过将 unique
设置为 true,然后第二个Post模型将 sluggify 。 如果有一个具有相同标题的第三个文章,那么它将sluggify到"my-blog-post-2"等。 每个后续模型将得到附加到蛞蝓末尾的增量值,从而确保唯一性。
如果要使用不同的方法识别唯一性( 自动递增整数以外的其他),可以以将 uniqueSuffix
配置设置为生成"唯一"值的函数或者可以调用。
该函数应采用三个参数: 基塞( 。例如 。非唯一的蛞蝓),分隔符串和所有它的他塞子串的IlluminateSupportCollection
,以同一个塞子开始。 然后可以以执行任何你想要创建的新后缀,该后缀没有被集合中的任何 slugs 使用。 例如如果你想使用字母代替数字作为后缀,这是实现以下目的的一种方法:
'uniqueSuffix'=>function ($slug, $separator, Collection$list) {$size=count($list);returnchr($size+96);}
设置为 true
也将在尝试强制唯一性时检查已经删除的模型。 这只影响使用了 softDelete 特性的Eloquent模型。 默认为 false
,因此在检查唯一性时,软删除的模型不计数。
绝对不允许作为 slugs的值,以防止与现有路由或者控制器方法的冲突。等等 。 这可以是 array,也可以是返回 array的闭包。 默认为 null
: 没有保留的鼻涕虫名称。
如果你真的懒惰,软件包支持一个真正简短的配置语法:
publicfunctionsluggable() {return ['slug' ];}
这将使用 app/config/sluggable.php
的所有缺省选项,使用模型方法的__toString()
作为源,并将slug存储在 slug
字段中。
有时,配置选项对于复杂需求来说是不够的( 比如 。 也许唯一性测试需要考虑其他属性) 。
在这种情况下,包提供了of工作流的挂钩,可以以在每个模型中使用自己的函数。
/** * @param CocurSlugifySlugify $engine * @param string $attribute * @return CocurSlugifySlugify*/publicfunctioncustomizeSlugEngine(Slugify$engine, $attribute){...}
如果在模型上存在这里方法,则可以在发生slugging之前自定义Slugify引擎。 这可能是你更改使用的字符映射或者更改语言文件 等等的地方。
你可以根据每个模型和每个属性( 也许你的模型有两个鼻涕虫字段,其中一个需要定制) 定制引擎。
请看一下 tests/Models/PostWithCustomEngine.php
举个例子。
/** * @param IlluminateDatabaseEloquentBuilder $query * @param IlluminateDatabaseEloquentModel $model * @param string $attribute * @param array $config * @param string $slug * @return IlluminateDatabaseEloquentBuilder*/publicfunctionscopeWithUniqueSlugConstraints(Builder$query, Model$model, $attribute, $config, $slug){...}
如果模型中存在这里范围,那么它也将应用到用于确定给定蛞蝓是否唯一的查询中。 传递给作用域的参数包括:
$model
--对象是 slugged
$attribute
--生成的蛞蝓字段,
$config
--给定模型和属性的配置 array
$slug
-- ( 在应用任何唯一后缀之前)
你可以随意在查询范围内使用这些值。 作为一个例子,看看 tests/Models/PostWithUniqueSlugConstraints.php
从它的标题生成标题的地方,但是这个标记是作者的作用范围。 所以Bob可以以有一个与pam的标题相同的贴子,但这两个都有相同的。
/** * Query scope for finding"similar" slugs, used to determine uniqueness. * * @param IlluminateDatabaseEloquentBuilder $query * @param string $attribute * @param array $config * @param string $slug * @return IlluminateDatabaseEloquentBuilder*/publicfunctionscopeFindSimilarSlugs(Builder$query, $attribute, $config, $slug){...}
这是为模型查找"相似"slugs的缺省范围。 基本上,包查找与 $slug
参数相同的现有 slugs,或者者从 $slug
以及分隔符字符串开始。 生成的集合是传递给 uniqueSuffix
处理程序的。
一般情况下,这里查询范围( 在Sluggable特性中定义的) 应该单独。 不过,你可以在你的模型中自由地。
向模型添加可选的SluggableScopeHelpers
特性使你可以使用模型及其 slugs 。 例如:
$post=Post::whereSlug($slugString)->get();$post=Post::findBySlug($slugString);$post=Post::findBySlugOrFail($slugString);
因为模型可以有多个蛞蝓,所以需要更多的配置。 有关所有详细信息,请参见 SCOPE-HELPERS.md 。
有关详细信息,请参阅 ROUTE-MODEL-BINDING.md 。
感谢的每个人,他们对这个项目有贡献 !
请使用 Github 报告 Bug,并提供注释或者建议。
有关如何更改更改的信息,请参阅 CONTRIBUTING.md 。
版权所有( c ) 2013 Colin Viebrock