thechrise / permalink
Laravel的永久链接路由系统。高级数据库驱动的路由。直接从数据库中处理您的永久链接和SEO参数。
Requires
- cviebrock/eloquent-sluggable: ^6.0|^7.0|^8.0|^9.0|^10.0
- illuminate/database: ^6.0|^7.0|^8.0|^9.0|^10.0
- illuminate/routing: ^6.0|^7.0|^8.0|^9.0|^10.0
- illuminate/support: ^6.0|^7.0|^8.0|^9.0|^10.0
- laravel/legacy-factories: ^1.1
- thechrise/seo-helper: ^6.0
Requires (Dev)
- mockery/mockery: ^1.1
- orchestra/testbench: ^4.0|^5.0|^6.0|^7.0
- phpunit/phpunit: ^9.0
This package is not auto-updated.
Last update: 2024-09-19 23:10:40 UTC
README
此包允许您直接从数据库创建动态路由,就像WordPress和其他CMS一样。
重要 虽然此包的功能非常简单,但有一些事情和良好实践需要考虑。我强烈建议您仔细阅读整个文档,以深入了解该包的工作原理,因为您将替换默认的Laravel路由系统,并且不想弄乱您的URL和SEO!
路线图
- 视觉SEO管理资源(进行中)
文档
安装
安装包
composer require thechrise/permalink
运行迁移
php artisan migrate
入门(请阅读)
此包直接从我们的数据库处理动态路由。也支持嵌套路由,因此我们可以轻松创建如 /jobs/frontend-web-developer
这样的路由。
大多数解决方案都与具有多态关系的模型紧密绑定,但是当处理没有模型的路由时,这并不灵活。此包支持两者,既支持绑定模型的路由,也支持常规路由。
基本上,此包将路由存储在包含每个路由信息的 permalinks
表中
- 别名
- 父级(嵌套路由的父级路由)
- 模型(如果有的话)
- 操作(控制器动作或模型默认动作)
- SEO选项(标题、元数据...)
默认情况下,此包将尝试在单个SQL查询中查找是否在 permalinks
表中存在与当前请求路径匹配的永久链接。这对于大多数用例来说是可以的。如果出于某种原因,您想将永久链接信息缓存到Laravel路由缓存中,请参阅缓存永久链接部分。
示例
让我们通过一个简单的示例来了解其内部工作原理
它将执行以下操作(此示例尽量明确,内部使用预加载和一些其他性能优化)
$router->get('users', 'UserController@index'); $router->get('users/israel-ortuno', 'UserController@show'); // Which will produce: // /users UserController@index // /users/israel-ortuno
注意: show
方法将接收用户作为参数 App\User::find(1)
,该路由绑定到该模型。
替换默认路由器
此包有自己的路由器,它扩展了默认的Laravel路由器。要替换默认路由器以使用此包中包含的扩展版本,您有两个选项
php artisan permalink:install {--default}
控制台将提示您两个选项
[0] Http/Kernel.php (Default & Recommended)
[1] bootstrap/app.php (Advanced)
选择适合您需求的选项。对于大多数情况,我推荐通过 Http\Kernel.php
进行操作。使用 --default
选项以避免阻塞提示(也可以使用默认Laravel命令的标志 --no-interaction
)。
这两种方法都将默认的Laravel路由器替换为此包提供的扩展版本,该版本包含永久链接管理逻辑。
重要 使用 Http\Kernel.php
或 bootstrap/app.php
。 不要 同时使用两者,因为这可能会导致意外的行为。
创建永久链接
动态路由系统的设置基本就这些了。让我们创建一个永久链接记录并测试一下!
Permalink::create([ 'slug' => 'home', 'action' => 'App\Http\Controllers\HomeController@index' ]); // Then visit /home
如果你的永久链接绑定到了一个模型(请参阅下一节),你可以按照以下方式创建你的永久链接记录
// Note: when using the User::create method, even if permalinkHandling (read more about it below) // is disabled, it will create the permalink record. $user = User::create([ 'name' => 'israel', 'permalink' => [ 'slug' => 'israel-ortuno', 'action' => 'user.show', 'seo' => [...] // omit this attribute until you read more about it ] ]); // Or $user->createPermalink([...);
当使用User::create
或createPermalink
时,如果你没有向permalink
键提供任何数据,它将自动使用默认数据。在创建永久链接时,数据数组中存在的任何键将覆盖其默认值。
注意:这仅在permalinkHandling
没有被禁用的情况下才能工作,更多关于它的信息请见下文。
更新永久链接
你可以像更新任何其他Eloquent模型一样轻松地更新一个永久链接。更新永久链接别名时,请务必小心,因为之前的URL将不再可用,并且这个包不处理301/302重定向。
重建最终路径(请阅读)
在更新别名时,包将递归地更新其嵌套永久链接的final_url
属性,用新的别名替换之前的别名段。您可以通过在config/permalink.php
配置文件中的rebuild_children_on_update
选项来控制这种行为。如果您想手动处理这项任务,请禁用此选项(不推荐)。
查看Devio\Permalink\Services\PathBuilder
类,以了解可用于执行手动更新的方法。
注意:请确保在当前请求的生命周期中重建子级的最终路径。
将模型绑定到永久链接
您可能想将永久链接绑定到模型资源,以便您可以创建一个唯一的URL来访问该特定资源。如果您想这样做,您只需要使用HasPermalinks
属性并实现模型上的Permalinkable
协议。
class User extends Model implements \Devio\Permalink\Contracts\Permalinkable; { use \Devio\Permalink\HasPermalinks; public function permalinkAction() { return UserController::class . '@show'; } public function permalinkSlug(): array { return ['entity.name']; } }
一旦您设置了这些,这个包将自动为该模型的每个新记录生成一个永久链接。
此外,Permalinkable
接口将强制您定义两个简单的方法
permalinkAction()
此方法将返回负责处理特定模型请求的默认控制器操作。模型本身将被注入到操作中(正如Laravel通常为路由模型绑定所做的那样)。
public function show($user) { return view('users.show', $user); }
注意:此操作将被永久链接记录中action
列中存在的任何现有值覆盖,因此,如果您需要,可以为同一模型具有多个操作。
permalinkSlug()
这个方法稍微有点复杂。由于所有别名任务都由出色的Sluggable包处理,我们必须向其sluggable
方法提供该包所需的信息。
永久链接模型将公开一个多态关系entity
到该模型。由于别名发生在Permalink
模型类中,我们必须指定哪个将成为别名的来源。您可以将entity
视为$this
,因此在这种情况下,entity.name
就相当于$this->name
。如果需要连接多个属性,请返回多个项。
['entity.name', 'entity.city']
注意:此方法应返回与Sluggable包兼容的数组,如果您想深入了解,请查看包文档。
自动处理永久链接
默认情况下,此包会根据绑定模型的操作创建/更新/删除您的永久链接。如果您不想这样做,并想决定何时为该特定模型创建/更新/删除永久链接的精确时刻,您可以通过两种方式禁用永久链接处理
// Temporally disable/enable: $model->disablePermalinkHandling(); $model->enablePermalinkHandling(); // Permanent disable or return a condition. // Create this method in you model: public function permalinkHanlding() { return false; }
创建
当您的资源触发 saved
事件时,将自动创建一个永久链接。除非您已向创建数组提供了 peramlink
键数组或使用了 setPermalinkAttribute
修改器,否则它将填充默认数据。
User::create(['name' => 'israel', 'permalink' => ['slug' => 'israel']]); // $user = new User; $user->permalink = ['slug' => 'israel']; $user->save();
如果禁用了 permalinkHandling
,您将能够决定何时创建永久链接
// Assume permalinkHanlding() returns false $user = User::create(['name' => 'israel']); // Perform other tasks... $user->createPermalink(); // Array is optional, provide data to override default values
注意:即使提供的数据中包含 permalink
键,永久链接记录仍会被创建。
更新
您可以像创建一样更新您的永久链接
$user = User::find(1); $user->updatePermalink(['seo' => ['title' => 'changed']]);
注意:默认情况下,如果您更新永久链接的 slug,它将递归地更新其所有嵌套元素的新段。有关更多信息,请参阅更新永久链接。
删除
如果您删除了一个绑定到永久链接记录的资源,该包将自动为我们销毁永久链接。再次提醒,如果您不想这样,并想自己处理,请禁用模型中的永久链接处理。
支持软删除
软删除支持是开箱即用的,因此如果您的资源被软删除,永久链接也会被软删除。如果您恢复资源,它也会自动恢复。禁用处理以手动处理此任务。
注意:如果您对资源调用 forceDelete()
,永久链接也将被永久删除。
嵌套永久链接
您可能希望有一个嵌套的永久链接结构,例如,对于您的博客。父级将是 /blog
,每篇文章都应该在这个路径中,因此您可以执行类似以下操作:
/blog -> Blog index, show all blog posts
/blog/post-1
/blog/post-2
...
此包会为您处理这些操作
自动永久链接嵌套
永久链接表 permalinks
有一个用于自动嵌套模型的列:parent_for
。此属性应包含您希望其成为父级的模型的完全限定名 (FQN) 类名。一旦设置,当您为指定的模型创建新的永久链接时,它将自动嵌套到给定的父级。
这通常是一个手动过程,您将在数据库中执行,所以它可能看起来像上面的示例。
禁用自动嵌套
如果您深入到这个包中并想手动管理永久链接的嵌套(您为什么要这样做?但以防万一...),请从配置中禁用此功能。
// Globally disable this feature for all models in your permalink.php config file 'nest_to_parent_on_create' => false // or config()->set('permalink.nest_to_parent_on_create', false); // Disable this feature for a particular model. Define this method in your model class: public function permalinkNestToParentOnCreate() { return false; }
手动嵌套
如果您希望手动将永久链接嵌套到其他内容中,您只需要将父级永久链接的 id
设置为子级永久链接的 parent_id
属性。
Permalink::create(['slug' => 'my-article', 'parent_id' => 1, 'action' => '...']);
永久链接操作
您永久链接记录上的 action
属性将提供当该永久链接与当前请求 URI 匹配时要处理请求的信息。
控制器作为动作
每个永久链接都应该有一个动作,特别是那些未绑定到模型的永久链接。您应该在永久链接记录的 action
列中指定 controller@action
。
如果有一个模型绑定到永久链接(实体),它将被作为参数传递到控制器动作。
class UserController { public function show($user) { return view('users.show', compact('user')); } }
视图作为动作
对于简单的用例,您可以将视图的路径指定为永久链接的动作。如上所述,永久链接实体(如果绑定到模型)也将在此视图中可用。
Permalink::create(['slug' => 'users', 'action' => 'users.index']);
如果绑定到模型...
Permalink::create(['slug' => 'israel-ortuno', 'entity_type' => User::class, 'entity_id' => 1, 'action' => 'users.show']); // And then in users/show.blade.php <h1>Welcome {{ $user->name }}</h1>
使用自定义控制器进行视图操作
在底层,视图操作由此包提供的控制器处理:Devio\Permalink\Http\PermalinkController
。如果需要,您可以使用自己的实现更新此控制器。也许您想应用一些中间件,或者以不同的方式解析视图...
您只需在 AppServiceProvider
(或其他)中将您的实现绑定到容器中。
// In your AppServiceProvider.php public function register() { $this->bind('Devio\Permalink\Http\PermalinkController', YourController::class); } // And then... class YourController { use Devio\Permalink\Http\ResolvesPermalinkView; public function __construct() { // Do your stuff. } }
这样,Laravel 现在将根据容器解析您的实现。
如果您想要为解析视图实现自己的版本,不要使用Devio\Permalink\Http\ResolvesPermalinkView
特性,并创建自己的view()
方法。
默认操作(在模型中)
如果您将模型绑定到永久链接,您可以在模型中定义默认操作,如下所示
public function permalinkAction() { return UserController::class . '@show'; // Or a view }
一旦实现Permalinkable
接口,此方法就是必需的。
重写默认操作
默认情况下,永久链接将根据永久链接实体的permlainkAction
方法解析操作。但是,如果您在永久链接记录的action
列中指定了一个值,它将覆盖默认操作。例如
class User extends Model { use HasPermalinks; ... public function permalinkAction() { return UserController::class . '@index'; } ... } // And then... $user = User::create([ 'name' => 'israel', 'permalink' => [ 'action' => 'user.show' ] ]); // Or just update the action attribute as you like
当访问此特定实体的永久链接时,user/show.blade.php
将负责处理请求,而不是默认控制器。这不是很酷吗?
删除永久链接
默认情况下,如果
支持软删除
缓存永久链接(请仔细阅读!)
如上所述,此包将在每个请求上执行单个SQL查询,以找到当前URI的匹配永久链接。这非常高效,对于大多数用例应该没问题。如果需要,此查询也可以被缓存以实现超快速访问。
您可以将永久链接路由缓存到默认的Laravel路由缓存系统中,但请注意,这将为permalinks
表中的每个记录生成一个路由,因此如果您有大量永久链接,我强烈不推荐这样做,因为您可能会在bootstrap/cache/routes.php
中结束于一个巨大的base64编码字符串,这可能会大大减慢应用程序的引导速度。对您打算缓存的路线数量进行一些测试,以了解您是否真的提高了性能。
为了缓存永久链接,您只需将整个permalinks
数据集加载到路由器中,然后运行路由缓存命令
Router::loadPermalinks(); Artisan::call('route:cache');
您可以创建一个命令来执行这两个操作或任何您认为合适的事情。从现在起,每当永久链接记录被更新时,您都必须手动更新此缓存。
处理SEO属性
如果无法为每个永久链接记录配置SEO属性,此包将不完整!它几乎毫无用处!
自动SEO生成
对于SEO标签生成,使用ARCANDEV/SEO-Helper。此包提供了一套强大的工具来管理您的SEO元标签。
{
"meta": {
"title": "Specific title", // The <title>
"description": "The meta description", // The page meta description
"robots": "noindex,nofollow" // Robots control
},
"opengraph":{
"title": "Specific OG title", // The og:title tag
"description": "The og description", // The og:description tag
"image": "path/to/og-image.jpg" // The og:image tag
},
"twitter":{
"title": "Specific Twitter title", // The twitter:title tag
"description": "The twitter description", // The twitter:description tag
"image": "path/to/og-image.jpg" // The twitter:image tag
}
}
注意:这只是最常见标签的一个示例,但您可以使用ARCANDEV/SEO-Helper支持的任何类型的标签(索引、noindex...),只需确保正确嵌套即可。
为了在HTML中渲染所有这些内容,您应该将以下内容添加到您的<meta>
<head> {!! seo_helper()->render() !!} </head>
或者
<head> {{ seo_helper()->renderHtml() }} </head>
请访问SEO-Helper – Laravel Usage了解有关渲染什么和如何渲染的更多信息。
了解其工作原理
底层,此JSON结构在调用不同的SEO助手(元数据、opengraph和twitter)。让我们了解
{ "title": "Generic title", "image": "path/to/image.jpg", "description": "Generic description", "meta": { "title": "Default title", }, "opengraph": { "image": "path/to/og-image.jpg" } }
此结构将允许您为所有构建器设置title
的基准值,同时仅更改元部分的标题。同样,图像,Twitter和OpenGraph将继承父图像,但OpenGraph将替换其构建器上的图像。这样,您将能够在每个部分上显示不同的信息!
这将调用来自 SeoMeta
辅助类的 setTitle 和来自 SeoOpenGraph
辅助类的 setImage。对于Twitter也是如此。花点时间审查这三个契约,以便了解所有可用方法
为了匹配任何辅助方法,每个JSON选项都将转换为以 set
和 add
为前缀的 studly_case
,因此 title
将转换为 setTitle
,而 google_analytics
将转换为 setGoogleAnalytics
。这有多么酷?
所有方法都是通过 call_user_func_array
调用的,因此如果选项包含一个数组,每个键都将作为参数传递给辅助方法。参见 setTitle
或 addWebmaster
,这允许多个参数。
填充SEO属性
您只需通过传递包含数据的数组到 seo
属性,就可以指定您永久链接的SEO属性
Peramlink::create([ 'slug' => 'foo', 'seo' => [ 'title' => 'this is a title', 'description' => 'this is a description', 'opengraph' => [ 'title' => 'this is a custom title for og:title' ] ] );
使用默认内容填充SEO属性
通常,您希望直接从您绑定模型的信息自动填充您的SEO信息。您可以通过在模型中创建以下所示的回退方法来实现这一点
public function getPeramlinkSeoTitleAttribute() { return $this->name; } public function getPermalinkSeoOpenGraphTitleAttribute() { return $this->name . ' for OpenGraph'; }
如果这些回退确实存在,并且该字段的值在创建永久链接时未提供,则将使用这些回退。请注意,这些方法应作为Eloquent访问器调用。使用 permalinkSeo 前缀,然后是到默认值的路径,以 StudlyCase 的形式,例如
seo.title => getPermalinkSeoTitleAttribute()
seo.description => getPermalinkSeoDescriptionAttribute()
seo.twitter.title => getPermalinkSeoTwitterTitleAttribute()
seo.twitter.description => getPermalinkSeoTwitterDescriptionAttribute()
seo.opengraph.title => getPermalinkSeoTwitterOpenGraphAttribute()
seo.opengraph.description => getPermalinkSeoOpenGraphDescriptionAttribute()
包将查找任何匹配的方法,因此您可以创建尽可能多的方法,以满足您的SEO设置需求,即使您只是创建自定义元标签,getPermalinkMyCustomMetaDescriptionAttribute
也会匹配,如果存在 seo.my.custom.meta.description
对象。
SEO构建器
为了提供更多的灵活性,方法调用通过3个类(每个辅助类一个)进行管道传输,称为Builders。这些构建器负责调用ARCANDEV/SEO-Helper包的正确方法。
如果这些构建器中的任何方法与JSON选项匹配,则包将执行该方法,而不是默认行为,即调用(如果存在)来自 SEO-Helper 包的方法。
以 MetaBuilder 为例进行审查。此构建器包含一个 setCanonical
方法,该方法基本上用作 setUrl
的别名(仅为了更明确)。
扩展构建器
为了修改这些构建器中的任何行为的任何一种,您可以创建自己的构建器,该构建器应扩展 Devio\Permalink\Contracts\SeoBuilder
接口或继承 Devio\Permalink\Builders\Builder
类。
一旦创建了您自己的构建器,只需将其替换为Container中的默认构建器。将以下内容添加到您应用程序中任何服务提供商的 register
方法中
// Singleton or not, whatever you require $this->app->singleton("permalink.meta", function ($app) { // meta, opengraph, twitter or base return new MyCustomBuilder; // Or if you are inheriting the default builder class return (new MyCustomBuilder($app->make(SeoHelper::class))); });
如果您希望使用其他包生成SEO元标签,则扩展和修改构建器可以做到这一点。
禁用SEO生成
如果您希望防止渲染三个构建器(元数据、OpenGraph或Twitter)中的任何一个,只需将其JSON选项设置为false
{ "meta": { }, "opengraph": false, "twitter": false }
这将禁用OpenGraph和Twitter构建器的执行。