sebastiansulinski / laravel-routes
Laravel 的路由集合和路由模型绑定包装器
Requires
- php: >=5.4.0
- illuminate/routing: ^5.0
This package is auto-updated.
Last update: 2020-07-28 13:07:32 UTC
README
[已废弃] 此仓库不再维护
虽然此项目在旧版 Laravel 中仍然可用,但其依赖项已不再是最新的。您仍然可以探索、学习和使用此处提供的代码。
路由集合
创建一个新目录来存储您应用程序的所有路由集合 - 例如,可以在 app/Http 下的名为 Routes/Collections 的目录中。
app/Http/Routes/Collections
在目录内部创建一个新类,该类将与您的系统给定部分一起使用 - 例如,对于您应用程序的前端部分,我们使用 FrontCollection.php 并将其放入另一个目录中 - 为了区分不同的部分,因为这一个属于前端,所以我们称之为 Front。
app/Http/Routes/Collections/Front/FrontCollection.php
新的 FrontCollection 类将扩展 SSD\LaravelRoutes\RouteCollectionFactory,并需要有一个名为 getNameSpace 的方法,该方法返回当前命名空间,该命名空间将用于在 app/Http/Routes/Collections/Front 目录中创建每个类的完全限定名。
// app/Http/Routes/Collections/Front/FrontCollection.php
namespace App\Http\Routes\Collections\Front;
use SSD\LaravelRoutes\RouteCollectionFactory;
class FrontCollection extends RouteCollectionFactory
{
protected static function getNameSpace()
{
return __NAMESPACE__;
}
}
在相同的目录中为每个路由集合创建一个新文件 - 例如,对于前端部分的 Blog 模块,您可以使用
// app/Http/Routes/Collections/Front/Blog.php
namespace App\Http\Routes\Collections\Front;
use SSD\LaravelRoutes\RouteCollectionContract;
class Blog implements RouteCollectionContract
{
public function routes()
{
app('router')->group(['prefix' => 'blog'], function() {
app('router')->get('/', 'BlogController@index');
app('router')->get('latest', 'BlogController@latest');
app('router')->post('comment', 'BlogController@addComment');
app('router')->get('comment/{id}', 'BlogController@showComment');
});
}
}
并为表单提交方法的 Contact 控制器可能还需要另一个
// app/Http/Routes/Collections/Front/Contact.php
namespace App\Http\Routes\Collections\Front;
use SSD\LaravelRoutes\RouteCollectionContract;
class Contact implements RouteCollectionContract
{
public function routes()
{
app('router')->group(['prefix' => 'contact'], function() {
app('router')->get('/', 'ContactController@index');
app('router')->post('/', 'ContactController@submit');
});
}
}
现在您只需要在您的 app/Http/routes.php 文件中做的是
use App\Http\Routes\Collections\Front\FrontCollection;
FrontCollection::blog();
FrontCollection::contact();
FrontCollection 上的神奇静态方法名称是 camelCase 格式的集合类名称 - 例如,名称为 FoodRecepies 的集合将被称为 FrontCollection::foodRecepies(),依此类推。
如果您想使您的 routes.php 文件更加整洁,您可以创建每个部分的集合主,然后将所有单独的路由集合包含在其中
// app/Http/Routes/Collections/Front/Master.php
namespace App\Http\Routes\Collections\Front;
use SSD\LaravelRoutes\RouteCollectionContract;
class Master implements RouteCollectionContract
{
public function routes()
{
FrontCollection::blog();
FrontCollection::contact();
}
}
并且对于 Admin 部分(请确保您首先创建了 AdminCollection)
// app/Http/Routes/Collections/Admin/Master.php
namespace App\Http\Routes\Collections\Admin;
use SSD\LaravelRoutes\RouteCollectionContract;
class Master implements RouteCollectionContract
{
public function routes()
{
app('router')->group(
[
'prefix' => 'admin',
'namespace' => 'Admin'
],
function() {
AdminCollection::auth();
app('router')->group(
[
'middleware' => ['admin']
],
function() {
AdminCollection::blog();
AdminCollection::pages();
}
);
}
);
}
}
然后只需在 routes.php 中调用它
use App\Http\Routes\Collections\Front\FrontCollection;
use App\Http\Routes\Collections\Admin\AdminCollection;
FrontCollection::master();
AdminCollection::master();
自定义异常
抽象的 SSD\LaravelRoutes\RouteCollectionFactory 类可以抛出 SSD\LaravelRoutes\Exceptions\InvalidClassName 异常,当静态方法名称与现有类不匹配时,或者当您忘记在扩展 SSD\LaravelRoutes\RouteCollectionFactory 的类上声明 getNameSpace() 方法时,抛出 SSD\LaravelRoutes\Exceptions\MissingNamespace 异常。
路由模型绑定
路由模型绑定允许您分组模型绑定。
首先,在 app/Http/Routes 下创建一个名为 ModelBindings 的新目录
app/Http/Routes/ModelBindings
在此目录中创建一个与您要定义绑定的模型相对应的类 - 例如,如果您有一个名为 Blog 的模型,您想要定义两个绑定 - 一个用于 blog_id,另一个用于 blog_slug
app('router')->get('blog/{blog_id}', 'BlogController@edit');
app('router')->get('blog/{blog_slug}', 'BlogController@show');
您的模型看起来可能是这样的
// app/Http/Routes/ModelBindings/BlogBinder.php
namespace App\Http\Routes\ModelBindings;
use Illuminate\Routing\Router;
use SSD\LaravelRoutes\RouteModelBinderContract;
use App\Blog;
class BlogBinder implements RouteModelBinderContract
{
public function bind(Router $router)
{
$router->model('blog_id', Blog::class);
// for version of PHP lower than 5.6 use:
// $router->model('blog_id', 'App\Blog');
$router->bind('blog_slug', function($slug) {
return $this->recordBySlug($slug);
});
}
protected function recordBySlug($slug)
{
return Blog::whereSlug($slug)->firstOrFail();
}
}
将scopeWhereSlug()方法添加到您的Blog模型中(或者,如果您在多个模型上使用slug,可以将其提取到Trait中)。
// app/Blog.php
namespace App;
class Blog extends Model
{
protected $table = 'blog';
public function scopeWhereSlug($query, $slug)
{
return $query->where('slug', '=', $slug);
}
}
现在,有了BlogBinder,我们可以将其添加到`app/Providers/RouteServiceProvider.php`。
// app/Providers/RouteServiceProvider.php
namespace App\Providers;
use Illuminate\Routing\Router;
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;
use SSD\LaravelRoutes\RouteModelBinderFactory;
use App\Http\Routes\ModelBindings\BlogBinder;
class RouteServiceProvider extends ServiceProvider
{
protected $namespace = 'App\Http\Controllers';
public function boot(Router $router)
{
parent::boot($router);
RouteModelBinderFactory::bind(new BlogBinder, $router);
}
public function map(Router $router)
{
$router->group(['namespace' => $this->namespace], function ($router) {
require app_path('Http/routes.php');
});
}
}
模型绑定提示
您更有可能在前端应用中使用slug - 所以为了稍微提高性能,让我们为slug绑定缓存模型。为此 - 在App\Http\Routes\ModelBindings下创建一个新的BaseBinder类,并为了方便起见 - 让我们使用nespot/carbon包。首先使用composer添加Carbon依赖。
composer require nesbot/carbon
现在创建一个具有cache方法的BaseBinder类。我只为一天进行缓存,但您可以根据需要将其设置得更长。
// app/Http/Routes/ModelBindings/BaseBinder.php
namespace App\Http\Routes\ModelBindings;
use Carbon\Carbon;
abstract class BaseBinder {
protected function cache($key, callable $default)
{
$value = app('cache.store')->get($key);
if (is_null($value)) {
$arguments = func_get_args();
$value = call_user_func_array($default, array_splice($arguments, 2));
app('cache.store')->put($key, $value, Carbon::now()->addDay(1));
}
return $value;
}
}
最后修改BlogBinder类
// app/Http/Routes/ModelBindings/BlogBinder.php
namespace App\Http\Routes\ModelBindings;
use Illuminate\Routing\Router;
use SSD\LaravelRoutes\RouteModelBinderContract;
use App\Blog;
class BlogBinder extends BaseBinder implements RouteModelBinderContract
{
public function bind(Router $router)
{
$router->model('blog_id', Blog::class);
$router->bind('blog_slug', function($slug) {
return $this->cache(
'blog.slug.'.$slug,
[
$this,
'recordBySlug'
],
$slug
);
});
}
protected function recordBySlug($slug)
{
return Blog::whereSlug($slug)->firstOrFail();
}
}
现在,您的模型绑定将首先从数据库中提供,然后,每次后续调用都将从缓存中读取,持续时间为一天。请确保在更新记录时,您也更新缓存的版本 - 或者简单地删除相应键的缓存。