3

Symfony2 で管理するのが非常に簡単な、特定のエンティティを含む定義済みのページと、異なるレイアウトのコンテンツ ページの両方を表示する必要がある現在のプロジェクトがあります。

ルーティング システムを構築しようとすると問題が発生します。

たとえば、ニュースのあるページを表示する必要がある場合、次のような新しいルートでバンドルのルーターを更新したいと思います。

my_bundle_news_page:
    pattern: /news
    defaults:
        _controller: MyBundle:NewsController:indexAction

しかし、多くのレベルで完全にカスタムの URL を持つ動的ルーターを管理するにはどうすればよいでしょうか?

オプションの「親子」関係の自己参照である「ページ」エンティティがあるとします。この特定のルーティングに任意の構成 YAML ファイルを使用できるとは思いませんか?!

my_bundle_custom_page:
    pattern: /{slug}
    defaults:
        _controller: MyBundle:PageController:showAction

これにより、すべての第 1 レベルのページがバインドされます。

/プロジェクト

/約

/コンタクト

/私たちのプロジェクト

たとえば、次のようなスラッグで表示されるページはどうでしょうか。

/私たちのプロジェクト/健康

実際、どの URL...

/{slug-level1}/{slug-level2}/{slug-level3} など

ページが変更され、ウェブマスタリングから更新されることが想定されているためです。

{slug} をデータベース フィールド (エンティティ プロパティ) と比較するルーターを用意するのが最善の方法だと思います。

Symfony-CMF docで、ルートプロバイダーに基づいたサービスを作成できることを読みました。

namespace MyBundle\Routing;

use Symfony\Component\Routing\RouteCollection;
use Symfony\Component\Routing\Route as SymfonyRoute;

use MyBundle\Entity\PageRepository;

class RouteProvider extends PageRepository {
    public function findPageBySlug($slug)
    {
        // Find a page by slug property
        $page = $this->findOneBySlug($slug);

        if (!$page) {
            // Maybe any custom Exception
            throw $this->createNotFoundException('The page you are looking for does not exists.');
        }

        $pattern = $page->getUrl(); // e.g. "/first-level/second-level/third-level"

        $collection = new RouteCollection();

        // create a new Route and set our page as a default
        // (so that we can retrieve it from the request)
        $route = new SymfonyRoute($pattern, array(
            'page' => $page,
        ));

        // add the route to the RouteCollection using a unique ID as the key.
        $collection->add('page_'.uniqid(), $route);

        return $collection;
    }
}

しかし、それをサービスとして設定する方法は? いくつかの要件はありますか? リクエストが呼び出されたときに RouteCollection にルートを追加しますか?

そして、この方法で任意のルートをバインドできますか?

編集: 私のバンドルの services.yml

parameters:
    cmf_routing.matcher.dummy_collection.class: Symfony\Component\Routing\RouteCollection
    cmf_routing.matcher.dummy_context.class: Symfony\Component\Routing\RequestContext
    cmf_routing.generator.class: Symfony\Cmf\Bundle\RoutingBundle\Routing\ContentAwareGenerator
    cmf_routing.nested_matcher.class:  Symfony\Cmf\Component\Routing\NestedMatcher\NestedMatcher
    cmf_routing.url_matcher.class:  Symfony\Cmf\Component\Routing\NestedMatcher\NestedMatcher
    fsbcms.chain_router.class: Symfony\Cmf\Component\Routing\ChainRouter
    fsbcms.route_provider.class: FSB\CMSBundle\Routing\RouteProvider
    fsbcms.dynamic_router.class: Symfony\Cmf\Component\Routing\DynamicRouter
    fsbcms.route_entity.class: null

services:
    fsbcms.router:
        class: %fsbcms.chain_router.class%
        arguments:
            - "@logger"
        calls:
            - [setContext, ["router.request_context"]]
    fsbcms.route_provider:
        class: "%fsbcms.route_provider.class%"
        arguments:
            - "@doctrine"
    cmf_routing.matcher.dummy_collection:
        class: "%cmf_routing.matcher.dummy_collection.class%"
        public: "false"
    cmf_routing.matcher.dummy_context:
        class: "%cmf_routing.matcher.dummy_context.class%"
        public: false
    cmf_routing.generator:
        class: "%cmf_routing.generator.class%"
        arguments:
            - "@fsbcms.route_provider"
            - "@logger"
        calls:
            - [setContainer, ["service_container"]]
            - [setContentRepository, ["cmf_routing.content_repository"]]
    cmf_routing.url_matcher:
        class: "%cmf_routing.url_matcher.class%"
        arguments: ["@cmf_routing.matcher.dummy_collection", "@cmf_routing.matcher.dummy_context"]
    cmf_routing.nested_matcher:
        class: "%cmf_routing.nested_matcher.class%"
        arguments: ["@fsbcms.route_provider"]
        calls:
            - [setFinalMatcher, ["cmf_routing.url_matcher"]]
    fsbcms.dynamic_router:
        class: "%fsbcms.dynamic_router.class%"
        arguments:
            - "@router.request_context"
            - "@cmf_routing.nested_matcher"
            - "@cmf_routing.generator"
        tags:
            - { name: router, priority: 300 }
4

1 に答える 1

3

Symfony CMF ルーティング コンポーネントと CmfRoutingBundle (symfony でコンポーネントを実装するため) を参照することをお勧めします。

ルーティング コンポーネントはチェーン ルーターを使用します。これはこの質問には関係ありませんが、知っておくとよいでしょう。チェーン ルーターは、ルーターのキューをチェーンします。このコンポーネントは、NestedMatcher を使用する DynamicRouter を提供します。それはまさにあなたが望むものです。

NestedMatcher は Route プロバイダーを使用して、動的ソース (データベースなど) からルートを取得します。質問で Route プロバイダーの例を示しています。

さらに、FinalMatcher を使用してルートを照合します。Symfony\Cmf\Component\Routing\NestedMatcher\UrlMatcherあまり難しいことをしていないので、 のインスタンスを渡すだけでかまいません。

RoutingBundleのドキュメントを見て、チェーン ルーターをアクティブにする方法を学び、ルートをロードしてサービスを作成するルート プロバイダーを作成します。

acme_routing.route_provider:
    class: Acme\RoutingBundle\Provider\DoctrineOrmProvider
    arguments: ["@doctrine"]

これで、NestedMatcher サービスを作成できます。

acme_routing.url_matcher:
    class: Symfony\Cmf\Component\Routing\NestedMatcher\UrlMatcher
    arguments: ["@cmf_routing.matcher.dummy_collection", "@cmf_routing.matcher.dummy_context"]

acme_routing.nested_matcher:
    class: Symfony\Cmf\Component\Routing\NestedMatcher
    arguments: ["@acme_routing.route_provider"]
    calls:
        - [setFinalMatcher, ["acme_routing.url_matcher"]]

次に、DynamicRouter を登録してチェーンに入れます。

acme_routing.dynamic_router:
    class: Symfony\Cmf\Component\Routing\DynamicRouter
    arguments:
        - "@router.request_context"
        - "@acme_routing.nested_matcher"
        - "@cmf_routing.generator"
    tags:
        - { name: router, priority: 300 }

これで動作し、データベースからルートをロードしてリクエストと照合するはずです。

于 2013-07-14T15:39:07.853 に答える