在Laravel 5.2中模仿Drupal url别名

时间:2016-10-11 11:24:12

标签: php laravel drupal routing

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

例如:

/ category / hello =>节点/ 5

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

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

我已经看了一眼路由器。没有任何事件真正发挥作用。我想避免的是将每个排列添加为静态路由。我想这是完全动态的。

我正在阅读中间件,重定向会起作用,但不知道这是否是最好的路线。请记住,别名可以是任何东西。没有任何固定模式。

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

实施例

/ sports / football / nfl => \ APP \ HTTP \控制器\类别:: LP(2)

甚至像:

/ sports / football / nfl /:game / lines => \ APP \ HTTP \控制器\线:: LP(:游戏)

但是,我不想在数据库中进行每个排列。只是基础,并允许/ sports / football / nfl / *之后的所有内容通过一个完全不同的位置。

如果我记得在Symfony中,可以使用自定义路径匹配器来完成。但是,我在Laravel看不到类似的东西。除非我只是遗漏了什么。看起来你要么添加一条静态路由,要么就是一无所有,但我还没有深入研究该代码,所以可能是错误的。

1 个答案:

答案 0 :(得分:0)

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

自定义路线     

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));

    }

}

我可能会对此进行扩展,但这是完成此操作的基本方法。