sebastiansulinski/laravel-routes

该包已被废弃,不再维护。未建议替代包。

Laravel 的路由集合和路由模型绑定包装器

1.0.0 2015-06-21 10:55 UTC

This package is auto-updated.

Last update: 2020-07-28 13:07:32 UTC


README

No longer maintained

[已废弃] 此仓库不再维护

虽然此项目在旧版 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();

    }


}

现在,您的模型绑定将首先从数据库中提供,然后,每次后续调用都将从缓存中读取,持续时间为一天。请确保在更新记录时,您也更新缓存的版本 - 或者简单地删除相应键的缓存。