Symfony CMF Dynamic Router с прослушивателем запросов ядра для многосайтового приложения

Извиняюсь за длинный пост, чувствую, что я спустился сюда по кроличьей норе и изо всех сил пытаюсь найти решение, которое работает.

Я создаю приложение Symfony (2.6), в котором я хотел бы поддерживать несколько магазинов, каждый из которых обладает уникальными продуктами, например, с использованием поддоменов.

http://stores.com                     - Primary store landing page
http://stores.com/first-product       - Product only available on store.com
http://nicks.stores.com               - Nicks store landing page
http://nicks.stores.com/first-product - Different product from the above example, only available on nicks.stores.com

Обработка поддоменов

Я успешно установил целевые страницы магазина, используя сопоставление хостов на маршрутизаторе Symfony по умолчанию (http://symfony.com/doc/current/components/routing/hostname_pattern.html).

С прослушивателем событий, который выбирает поддомен магазина и добавляет его в сервис (идея взята из http://knpuniversity.com/screencast/question-answer-day/symfony2-dynamic-subdomains).

Служба хранилища (обратите внимание, я использую JMSDiExtraBundle для определения служб с помощью аннотаций):

/**
* @Service("store_service")
*/
class StoreService
{
protected $storeCurrent;

public function getCurrentStore()
{
return $this->storeCurrent;
}

public function setCurrentStore(Store $store)
{
$this->storeCurrent = $store;
return $this;
}
}

Прослушиватель событий для извлечения субдомена из запроса и добавления в сервис, если он существует

/**
* @Service
*/
class CurrentStoreListener
{
/**
* @var EntityManager
*/
protected $em;

/**
* @var StoreService
*/
protected $storeService;

/**
* @DI\InjectParams({
*      "em" = @DI\Inject("doctrine.orm.entity_manager"),
*      "storeService" = @DI\Inject("store_service")
* })
*/
public function __construct(EntityManager $em, StoreService $storeService)
{
$this->em = $em;
$this->storeService = $storeService;
}

/**
* @Observe("kernel.request", priority=31)
*/
public function onKernelRequest(GetResponseEvent $event)
{
$store = $this->em->getRepository('StoreBundle:Store')
->findByDomainNotDeleted($event->getRequest()->getHost());

if (!$store) {
throw new NotFoundHttpException('No such store exists');
}

$this->storeService->setCurrentStore($store);
}
}

Пример действия контроллера с маршрутом с использованием SensioFrameworkExtraBundle:

class StoreController extends Controller
{
/**
* @DI\Inject("doctrine.orm.entity_manager")
* @var EntityManager
*/
private $em;

/**
* @DI\Inject("store_service")
* @var StoreService
*/
protected $storeService;

/**
* @Route("/", name="store_index")
* @Template
*/
public function indexAction()
{
$store = $this->storeService->getCurrentStore();
$products = $this->em->getRepository('StoreBundle:Product')->findAllForStoreInOrder($store);

return [
'store' => $store,
'products' => $products
];
}
}

Это все работает отлично. 🙂

Обработка динамических товарных маршрутов для магазинов

Здесь я начинаю испытывать проблемы, потому что прослушиватель событий (как показано выше) не вызывается достаточно рано, поэтому он доступен для динамического маршрутизатора ниже.

Этот динамический маршрутизатор работал просто отлично, когда приложение было единым хранилищем, ниже был построен с использованием динамического маршрутизатора CMF (http://symfony.com/doc/current/cmf/book/routing.html)

# app/config/config.yml

cmf_routing:
dynamic:
enabled:                      true
route_provider_service_id:    store.product_router
chain:
routers_by_id:
router.default:             32
cmf_routing.dynamic_router: 30
/**
* @Service("store.product_router")
*/
class ProductRouter implements RouteProviderInterface
{
/**
* @var EntityManager
*/
protected $em;

/**
* @var StoreService
*/
protected $storeService;

/**
* @DI\InjectParams({
*      "em" = @DI\Inject("doctrine.orm.entity_manager"),
*      "storeService" = @DI\Inject("store_service")
* })
*/
public function __construct(EntityManager $em, StoreService $storeService)
{
$this->em = $em;
$this->storeService = $storeService;
}

/**
* @param Request $request
* @return RouteCollection
*/
public function getRouteCollectionForRequest(Request $request)
{
$collection = new RouteCollection();

$product = $this->em->getRepository('StoreBundle:Product')
->findOneBySlugForStore(substr($request->getRequestUri(), 1), $this->storeService->getCurrentStore());

if (empty($product)) {
return $collection;
}

$route = new Route(
'/' . $product->getSlug(),
[
'_controller' => 'StoreBundle:Product:view',
'slug' => $product->getSlug()
]
);

$collection->add($product->getSlug(), $route);

return $collection;
}

public function getRouteByName($name, $params = [])
{
}

public function getRoutesByNames($names)
{
}
}

Я попытался изменить приоритеты служб, для меня должны работать следующие приоритеты:

32 — Маршрутизатор по умолчанию

31 — текущий слушатель магазина

30 — Динамический маршрутизатор

Любые предложения о том, как я могу получить доступ к текущему магазину внутри моего динамического маршрутизатора?

Поймите, я мог бы взломать это и просто извлечь запрос хоста и передать его в хранилище на динамическом маршрутизаторе, но это дополнительное объединение таблиц, которое я бы предпочел не видеть, так как у меня уже должна быть доступна сущность хранилища.

0

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]