malyusha / path-history
Laravel 包,允许您从属性创建嵌套/可读路径(urls)以用于您的 eloquent 模型。
Requires
- php: ^7.0
- illuminate/database: ^5.4 || ^5.5 || ^5.6 || ^5.7
- illuminate/routing: ^5.4 || ^5.5 || ^5.6 || ^5.7
- illuminate/support: ^5.4 || ^5.5 || ^5.6 || ^5.7
Requires (Dev)
- mockery/mockery: ^1.2
- orchestra/testbench: 3.5.*
- phpunit/phpunit: ^6.3|^7.0
README
路径历史
Laravel 包,允许您为 eloquent 模型创建嵌套/可读路径(urls)。
安装
在项目目录中运行 composer require malyusha/path-history
。
为什么?
有时您可能希望创建分类新闻/文章/产品页面,并看到最终 URL 形如 http(s)://your-domain.com/{category}/{product}
。那么,如何进行路由、解析此类模式?
- 为每个实体创建路由。因此,对于基础路由参数的每次更改,您都将更改其依赖项。
- 创建类别(们)的路由
Route::get('{category_slug}')->name('products_category')->uses('ProductCategoryController@showCategory');
- 然后创建产品路由
Route::get('{category_slug}/{product_identifier}')->name('product')->uses('ProductsController@showProduct');
但如果每个实体都有嵌套类别怎么办?好吧,我们可以处理它,只需在路由上添加带有模式的 where
条件:->where('category_slug', '[\w\-/_]+')
。因此,现在您的路由器将知道 category_slug
可以包含斜杠,但我们如何确定 category_slug
哪里结束,product_identifier
哪里开始?就是这样,我们需要给产品/文章路由添加前缀,以便解析器知道它的工作原理。
修改最后一个路由
Route::get('{category_slug}/p-{product_identifier}')->name('product')->uses('ProductsController@showProduct');
将给出我们想要的结果。
那么,这种方法的主要问题是什么?
- 每个实体都必须有自己的路由;
- 无法自动从旧 URL 重定向到新 URL。想象一下有两个类别(
black
、white
),每个类别有 20 个子类别。每个子类别有 ~20-40 个产品/文章。现在,您决定将类别black
改为black-color
,您将不得不将来自(20 * ~20-40)URL 的重定向添加到新 URL。 - 实体前缀为 2 级和以上。不是关键,但仍然是;
此包解决了此类路由和模型 URL 的问题
它如何工作?
- 包创建一个表,其中存储所有 "slugable" 实体的所有 URL;
- 您将特质添加到所有 "slugable" 实体中,并为相对实体确定少量逻辑;
- 您定义系统路由并包含包路由注册器;
- 为从 URL 解析的每种类型的实体定义控制器及其逻辑;
- 完成!
入门
- 运行
vendor:publish --tag=migrations --tag=config
发布 vendors。这将复制配置文件并生成包含新表创建的迁移文件。 - 运行
php artisan migrate
以运行生成的文件迁移; - 有关配置参数的详细说明,请参阅 配置 部分;
设置模型 URL 生成
- 在您的模型中包含
\Malyusha\PathHistory\HasPathHistory
特质;
<?php namespace App\Entities; use App\DescendantRetrievers\Shop\NestedSetDescendants; use App\DescendantRetrievers\Shop\ProductsOfCategory; class ProductCategory extends \Illuminate\Database\Eloquent\Model { use \Malyusha\PathHistory\HasPathHistory; protected $updatePathOnChangeAttributes = ['parent_id']; protected $parentPathRelation = 'parent'; protected $descendantRetrievers = [ NestedSetDescendants::class, ProductsOfCategory::class, ]; public function parent() { return $this->belongsTo(static::class, 'parent_id'); } public function shouldUseParentPaths(): bool { return ! $this->isRoot(); } public function isRoot(): bool { return $this->parent_id === null; } public function products(): \Illuminate\Database\Eloquent\Relations\HasMany { return $this->hasMany(Product::class); } }
如您所见,我们定义了一个使用我们的特质类别的模型。该特质将为当前和嵌套类别及其产品设置模型事件监听器以更新所有路径。您可能已经注意到我们为我们的模型定义了额外的属性,让我们更详细地看看它们
- 在您的路由文件中放置路由
<?php // web.php Route::get('/')->name('index')->uses('HomeController@showIndex'); // ... Other routes definitions ... // And here comes shop section Route::prefix('shop')->name('shop.')->group(function () { Route::get('/')->name('index')->uses('ShopController@index'); // Call dynamic router registration app('ph.router')->register(); });
- 在配置文件中将
shop
添加到paths
参数中。更详细的说明请见 此处。
就是这样!您已定义了模型、控制器和负责 URL 生成和处理的路由!
检索模型的 URL
您已经设置模型使用路径历史,您将需要检索其生成的URL。每个使用PathHistoryTrait的模型都有一个获取器用于path
属性。它会检查currentPath
关系是否已加载到模型中,并返回其链接。因此,如果您想使用完整URL,则需要预加载此关系。
// IndexController.php
public function showIndex() { $products = App\Entities\Product::with('currentPath')->get(); return view('index_page', ['products' => $products]); }
// index_page.blade.php
@extends('layouts.default') @section('content') <h1>Products</h1> @foreach($products as $product) <img src="{{ $product->getImage() }}}"> <a href="{{ route('shop.resolve', ['path' => $product->path]) }}">{{ $product->name }}</a> @endforeach @endsection
当产品路径关系加载时,其链接将包含指向产品页面的完整URL。
配置
在您的项目中发布供应商后,您可以在path_history.php
配置文件中找到包的配置。此文件包含每个参数的注释和描述,但在这里您可以找到有关它们的更详细信息。
table
- 存储所有使用特性模型的URL的表。
model
- PathHistoryContract
的实例。这是管理路径历史包逻辑的主要模型。如果您想自定义某些内容,请将其重定义为您自己的模型。
redurect_status
- 对于不再是当前路径的路径的重定向状态。默认为302,但您可以将它更改为301,例如,当您确信将永远不会恢复实体的旧URL。注意:它仅在您在Http\Kernel列表中添加重定向中间件时才有效。
paths
- 路径数组。这些是主要设置,显示您的应用程序应该如何管理配置模型类型的URL。为了简化,让我们看看paths
参数的示例配置。
<?php return [ // other params here... 'paths' => [ [ 'prefix' => 'news', 'types' => [ \App\Entities\Content\NewsCategory::class => \App\Http\Controllers\News\CategoryController::class, \App\Entities\Content\News::class => \App\Http\Controllers\News\NewsController::class, ] ], [ 'prefix' => 'products', 'types' => [ \App\Entities\Shop\Product::class => \Admin\Http\Controllers\Shop\ProductsController::class, \App\Entities\Shop\ProductCategory::class => \Admin\Http\Controllers\Shop\CategoryController::class, ], ], ], ];
如您所见,我们为2个部分定义了配置:news
和products
。让我们更详细地看看每个path
数组配置。
prefix
- 用于告诉包用于处理具体模型类型的根前缀,并在模型前缀匹配时调用其控制器。
types
- 在这里您需要定义要处理为数组的类型数组。如果您有处理所有类型实体的前缀的控制器,您可以将其定义为路径数组中的单独参数 - [controller => your_controller]
,并使types
参数为索引数组,其中模型作为值。
自动重定向
从路径历史中自动重定向到旧URL有两种选项。
从旧模型URL重定向
将Malyusha\PathHistory\Middleware\RedirectsFromOld
中间件添加到您的web
中间件组中的App\Http\Kernel
。这将使用户从模型旧的创建URL重定向到更改的URL(如果它们存在)。
假设您有如上所述的代码结构。您希望您的商店部分位于访问/shop
的地方。您创建了一个slug为men
的分类,因此您的分类页面将显示在/shop/men
。现在,您已创建了一个slug为boots
的嵌套分类,因此用户将看到男靴页面在/shop/men/boots
。您为这些分类创建了第一个产品 - "Awesome Black Boots",代码为awesome-bb
或只是靴子的供应商代码,这并不重要。这个产品在这页面上展示了2个月,您决定将分类代码更改为,例如,high-shoes
,但机器人(google bot、yahoo等)已经索引了您的旧URL。通常,您可以有一个单独的表来处理从旧到新的URL的重定向,并手动添加它们,但这个包可以为您处理。因此,当您将分类的slug更改为新的内容时,所有分类的后代URL(子分类、产品等)现在将重定向到新的URL。
所有系统URL的全局重定向
通过运行composer require spatie/laravel-missing-page-redirector
安装spatie/laravel-missing-page-redirector
。
在您需要从项目中原本不存在的旧页面进行重定向时,就需要使用这种重定向。例如,当您从旧版本的网站迁移到新版本时,需要保存所有已索引的页面并将它们重定向到新的页面。文档正在编写中...