在Laravel 5.2中模仿Drupal url别名


Imitating Drupal url aliases in Laravel 5.2

在Drupal中有一个简单的url重写系统,它在数据库中存储路径别名和实际路由。

例如:

/category/hello => node/5

我想在Laravel中模仿这个系统。

我知道如何创建数据库结构。我想要的建议实际上是重写和重新映射传入的请求。

我看了一眼路由器。没有特别突出的事件。我想避免的是将每个排列添加为静态路由。我希望这是完全动态的。

我正在阅读中间件与重定向将工作,但不知道如果这是最好的路线去。记住,假名可以是任何东西。没有固定的模式。

这样做的实际业务案例是应用程序具有分类层次结构,就像电子商务网站上的目录一样。对于每个路径,一个动态页面都需要存在,并且可能还允许传递到其他页面。

/sports/football/nfl => 'App'Http'Controllers'Category::lp(2)

甚至像

/sports/football/nfl/:game/lines => 'App'Http'Controllers' lines::lp(:game)

但是,我不希望在数据库中有每个排列。只有最基本的一个,允许/sports/football/nfl/*之后的所有内容通过到一个完全不同的位置。

如果我记得在Symfony中,这可以通过自定义路由匹配器来完成。然而,我在Laravel没有看到这样的情况。除非我错过了什么。看起来你要么添加一个静态路由,要么什么都不添加,但我还没有深入研究这段代码,所以可能是错误的。

我能够通过创建自己的自定义路由并手动添加到路由集合来实现动态路由系统。

自定义路径

use Illuminate'Routing'Route as BaseRoute;
use Modules'Catalog'Routing'Matching'CategoryValidator;
use Illuminate'Routing'Matching'MethodValidator;
use Illuminate'Routing'Matching'SchemeValidator;
use Illuminate'Routing'Matching'HostValidator;
use Illuminate'Http'Request;
use Modules'Event'Repositories'CategoryRepository;
use Illuminate'Routing'ControllerDispatcher;
/**
 * Special dynamic touting for catalog categories.
 */
class CategoryRoute extends BaseRoute {
    protected $validatorOverrides;
    /**
     * @param CategoryRepository
     */
    protected $categoryRepository;
    /**
     * Create a new Route instance.
     *
     * @param CategoryRepository $categoryRepository
     *   The category repository.
     */
    public function __construct(CategoryRepository $categoryRepository)
    {
        $this->categoryRepository = $categoryRepository;
        $action = [
            'uses'=> function() use ($categoryRepository) {
                $path = app('request')->path();
                $category = $categoryRepository->findOneByHierarchicalPath($path);
                $controller = app()->make('Modules'Catalog'Http'Controllers'Frontend'CategoryController');
                return $controller->callAction('getIndex', ['categoryId'=>$category->getId()]);
            }
        ];
        $action['uses']->bindTo($this);
        parent::__construct(['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE'],'_catalog_category',$action);
    }
    /**
     * Determine if the route matches given request.
     *
     * @param  'Illuminate'Http'Request  $request
     * @param  bool  $includingMethod
     * @return bool
     */
    public function matches(Request $request, $includingMethod = true)
    {
        $this->compileRoute();
        $validators = $this->getValidatorOverrides();
        foreach ($validators as $validator) {
            /*if (! $includingMethod && $validator instanceof MethodValidator) {
                continue;
            }*/
            if (! $validator->matches($this, $request)) {
                return false;
            }
        }
        return true;
    }
    /**
     * Get the route validators for the instance.
     *
     * @return array
     */
    public function getValidatorOverrides()
    {
        if (isset($this->validatorOverrides)) {
            return $this->validatorOverrides;
        }
        $this->validatorOverrides = [
            new MethodValidator, new SchemeValidator,
            new HostValidator, /*new UriValidator,*/
            new CategoryValidator($this->categoryRepository)
        ];
        return $this->validatorOverrides;
    }
}

自定义路由验证器

<?php
namespace Modules'Catalog'Routing'Matching;
use Illuminate'Routing'Matching'ValidatorInterface;
use Illuminate'Routing'Route;
use Illuminate'Http'Request;
use Modules'Event'Repositories'CategoryRepository;
class CategoryValidator implements ValidatorInterface
{
    protected $categoryRepository;
    public function __construct(CategoryRepository $categoryRepository) {
        $this->categoryRepository = $categoryRepository;
    }
    /**
     * Validate a given rule against a route and request.
     *
     * @param  'Illuminate'Routing'Route  $route
     * @param  'Illuminate'Http'Request  $request
     * @return bool
     */
    public function matches(Route $route, Request $request)
    {
        $path = $request->path() == '/' ? '/' : '/'.$request->path();
        $category = $this->categoryRepository->findOneByHierarchicalPath($path);
        return $category?true:false;
    }
}

为了满足类别存储库依赖关系的需求,我还必须创建一个订阅者,该订阅者在所有提供者启动后添加路由。简单地把它放在routes.php文件中是行不通的,因为不能保证在加载该文件时IoC的所有依赖项都配置好了。

引导用户

use Modules'Catalog'Routing'CategoryRoute;
use Modules'Event'Repositories'CategoryRepository;
use Illuminate'Support'Facades'Route as RouteFacade;
class BootstrapSubscriber {
    public function subscribe($events) {
        $events->listen(
            'bootstrapped: Illuminate'Foundation'Bootstrap'BootProviders',
            'Modules'Catalog'Subscribers'BootstrapSubscriber@onBootstrappedBootProviders'
        );
    }
    public function onBootstrappedBootProviders($event) {
        $categoryRepository = app(CategoryRepository::class);
        RouteFacade::getRoutes()->add(new CategoryRoute($categoryRepository));
    }
}

我可能会详细说明这一点,但这是基本的方法