vendor/ibexa/product-catalog/src/bundle/EventSubscriber/MainMenuSubscriber.php line 88

Open in your IDE?
  1. <?php
  2. /**
  3. * @copyright Copyright (C) Ibexa AS. All rights reserved.
  4. * @license For full copyright and license information view LICENSE file distributed with this source code.
  5. */
  6. declare(strict_types=1);
  7. namespace Ibexa\Bundle\ProductCatalog\EventSubscriber;
  8. use Ibexa\AdminUi\Menu\Event\ConfigureMenuEvent;
  9. use Ibexa\Bundle\Commerce\Eshop\Api\Configuration\CommerceSiteConfig;
  10. use Ibexa\Contracts\Core\Repository\ContentService;
  11. use Ibexa\Contracts\Core\Repository\Exceptions\NotFoundException;
  12. use Ibexa\Contracts\Core\Repository\Exceptions\UnauthorizedException;
  13. use Ibexa\Contracts\ProductCatalog\Permission\Policy\Commerce\AdministrateCurrencies;
  14. use Ibexa\Contracts\ProductCatalog\Permission\Policy\CustomerGroup\View as ViewCustomerGroup;
  15. use Ibexa\Contracts\ProductCatalog\Permission\Policy\Product\View as ViewProduct;
  16. use Ibexa\Contracts\ProductCatalog\Permission\Policy\ProductType\View as ViewProductType;
  17. use Ibexa\Contracts\ProductCatalog\PermissionResolverInterface;
  18. use Ibexa\Contracts\Taxonomy\Service\TaxonomyServiceInterface;
  19. use Ibexa\ProductCatalog\Config\ConfigProviderInterface;
  20. use JMS\TranslationBundle\Model\Message;
  21. use JMS\TranslationBundle\Translation\TranslationContainerInterface;
  22. use Knp\Menu\ItemInterface;
  23. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  24. final class MainMenuSubscriber implements EventSubscriberInterface, TranslationContainerInterface
  25. {
  26. // Main Menu / Product catalog
  27. public const ITEM_PRODUCT_CATALOG = 'main__product_catalog';
  28. // Main Menu / Product catalog / Products
  29. public const ITEM_PRODUCT_CATALOG_PRODUCTS = 'main__product_catalog__products';
  30. // Main Menu / Product catalog / Catalogs
  31. public const ITEM_PRODUCT_CATALOG_CATALOGS = 'main__product_catalog__catalogs';
  32. // Main Menu / Product catalog / Product Categories
  33. public const ITEM_PRODUCT_CATALOG_CATEGORIES = 'main__product_catalog__categories';
  34. // Main Menu / Product catalog / Settings
  35. public const ITEM_PRODUCT_GROUP_SETTINGS = 'main__product_catalog__group_settings';
  36. // Main Menu / Product catalog / Settings / Product Types
  37. public const ITEM_PRODUCT_CATALOG_PRODUCT_TYPES = 'main__product_catalog__product_types';
  38. // Main Menu / Product catalog / Settings / Attribute Groups
  39. public const ITEM_PRODUCT_CATALOG_ATTRIBUTE_GROUPS = 'main__product_catalog__attribute_groups';
  40. // Main Menu / Product catalog / Settings / Attributes
  41. public const ITEM_PRODUCT_CATALOG_ATTRIBUTES = 'main__product_catalog__attributes';
  42. // Main Menu / Product catalog / Customer Groups
  43. public const ITEM_PRODUCT_CATALOG_CUSTOMER_GROUPS = 'main__product_catalog__customer_groups';
  44. // Main Menu / Product catalog / Currencies
  45. public const ITEM_PRODUCT_CATALOG_CURRENCIES = 'main__product_catalog__currencies';
  46. // Main Menu / eCommerce
  47. public const ITEM_COMMERCE = 'main__commerce';
  48. private PermissionResolverInterface $permissionResolver;
  49. private ConfigProviderInterface $configProvider;
  50. private ?CommerceSiteConfig $commerceSiteConfig;
  51. private TaxonomyServiceInterface $taxonomyService;
  52. private ContentService $contentService;
  53. private string $productTaxonomyName;
  54. public function __construct(
  55. PermissionResolverInterface $permissionResolver,
  56. ConfigProviderInterface $configProvider,
  57. ?CommerceSiteConfig $commerceSiteConfig,
  58. TaxonomyServiceInterface $taxonomyService,
  59. ContentService $contentService,
  60. string $productTaxonomyName
  61. ) {
  62. $this->permissionResolver = $permissionResolver;
  63. $this->configProvider = $configProvider;
  64. $this->commerceSiteConfig = $commerceSiteConfig;
  65. $this->taxonomyService = $taxonomyService;
  66. $this->contentService = $contentService;
  67. $this->productTaxonomyName = $productTaxonomyName;
  68. }
  69. public static function getSubscribedEvents(): array
  70. {
  71. return [
  72. ConfigureMenuEvent::MAIN_MENU => ['onConfigureMainMenu', 15],
  73. ];
  74. }
  75. public function onConfigureMainMenu(ConfigureMenuEvent $event): void
  76. {
  77. $menu = $event->getMenu();
  78. $this->addCommerceMenu($menu);
  79. if ($this->configProvider->getEngineAlias() === null) {
  80. return;
  81. }
  82. $productCatalogRoot = $menu->addChild(
  83. self::ITEM_PRODUCT_CATALOG,
  84. [
  85. 'attributes' => [
  86. 'data-tooltip-placement' => 'right',
  87. 'data-tooltip-extra-class' => 'ibexa-tooltip--navigation',
  88. ],
  89. 'extras' => [
  90. 'icon' => 'product-catalog',
  91. 'orderNumber' => 80,
  92. 'routes' => [
  93. [
  94. 'pattern' => $this->getProductCatalogRoutePattern(),
  95. ],
  96. ],
  97. ],
  98. ]
  99. );
  100. if ($this->canViewProducts()) {
  101. $productCatalogRoot->addChild(
  102. self::ITEM_PRODUCT_CATALOG_PRODUCTS,
  103. [
  104. 'route' => 'ibexa.product_catalog.product.list',
  105. 'extras' => [
  106. 'routes' => [
  107. [
  108. 'pattern' => '~^ibexa\.product_catalog\.product\.~',
  109. ],
  110. ],
  111. 'orderNumber' => 10,
  112. ],
  113. ]
  114. );
  115. $productCatalogRoot->addChild(
  116. self::ITEM_PRODUCT_CATALOG_CATALOGS,
  117. [
  118. 'route' => 'ibexa.product_catalog.catalog.list',
  119. 'extras' => [
  120. 'routes' => [
  121. [
  122. 'pattern' => '~^ibexa\.product_catalog\.catalog\.~',
  123. ],
  124. ],
  125. 'orderNumber' => 20,
  126. ],
  127. ]
  128. );
  129. if ($this->configProvider->getEngineType() === 'local') {
  130. try {
  131. $entry = $this->taxonomyService->loadRootEntry($this->productTaxonomyName);
  132. $rootContent = $this->contentService->loadContentInfo($entry->content->id);
  133. $productCatalogRoot->addChild(
  134. self::ITEM_PRODUCT_CATALOG_CATEGORIES,
  135. [
  136. 'route' => 'ibexa.content.view',
  137. 'routeParameters' => [
  138. 'contentId' => $rootContent->id,
  139. 'locationId' => $rootContent->mainLocationId,
  140. ],
  141. 'extras' => [
  142. 'translation_domain' => 'ibexa_menu',
  143. 'orderNumber' => 25,
  144. 'taxonomy' => $this->productTaxonomyName,
  145. ],
  146. ]
  147. );
  148. } catch (UnauthorizedException|NotFoundException $exception) {
  149. // ignore
  150. }
  151. }
  152. }
  153. if ($this->canViewProductTypes()) {
  154. $groupSettingsRoot = $productCatalogRoot->addChild(
  155. self::ITEM_PRODUCT_GROUP_SETTINGS,
  156. [
  157. 'extras' => [
  158. 'orderNumber' => 30,
  159. ],
  160. ],
  161. );
  162. $groupSettingsRoot->addChild(
  163. self::ITEM_PRODUCT_CATALOG_PRODUCT_TYPES,
  164. [
  165. 'route' => 'ibexa.product_catalog.product_type.list',
  166. 'extras' => [
  167. 'routes' => [
  168. [
  169. 'pattern' => '~^ibexa\.product_catalog\.product_type\.~',
  170. ],
  171. ],
  172. 'orderNumber' => 40,
  173. ],
  174. ]
  175. );
  176. $groupSettingsRoot->addChild(
  177. self::ITEM_PRODUCT_CATALOG_ATTRIBUTE_GROUPS,
  178. [
  179. 'route' => 'ibexa.product_catalog.attribute_group.list',
  180. 'extras' => [
  181. 'routes' => [
  182. [
  183. 'pattern' => '~^ibexa\.product_catalog\.attribute_group\.~',
  184. ],
  185. ],
  186. 'orderNumber' => 20,
  187. ],
  188. ]
  189. );
  190. $groupSettingsRoot->addChild(
  191. self::ITEM_PRODUCT_CATALOG_ATTRIBUTES,
  192. [
  193. 'route' => 'ibexa.product_catalog.attribute_definition.list',
  194. 'extras' => [
  195. 'routes' => [
  196. [
  197. 'pattern' => '~^ibexa\.product_catalog\.attribute_definition\.~',
  198. ],
  199. ],
  200. 'orderNumber' => 30,
  201. ],
  202. ]
  203. );
  204. }
  205. $rootElement = $menu->getChild(self::ITEM_COMMERCE) ?? $productCatalogRoot;
  206. if ($this->canViewCustomerGroups()) {
  207. $rootElement->addChild(
  208. self::ITEM_PRODUCT_CATALOG_CUSTOMER_GROUPS,
  209. [
  210. 'route' => 'ibexa.product_catalog.customer_group.list',
  211. 'extras' => [
  212. 'routes' => [
  213. [
  214. 'pattern' => '~^ibexa\.product_catalog\.customer_group\.~',
  215. ],
  216. ],
  217. 'orderNumber' => 40,
  218. ],
  219. ]
  220. );
  221. }
  222. if ($this->canAdministrateCurrencies()) {
  223. $rootElement->addChild(
  224. self::ITEM_PRODUCT_CATALOG_CURRENCIES,
  225. [
  226. 'route' => 'ibexa.product_catalog.currency.list',
  227. 'extras' => [
  228. 'routes' => [
  229. [
  230. 'pattern' => '~^ibexa\.product_catalog\.currency\.~',
  231. ],
  232. ],
  233. 'orderNumber' => 50,
  234. ],
  235. ]
  236. );
  237. }
  238. }
  239. public static function getTranslationMessages(): array
  240. {
  241. return [
  242. (new Message(self::ITEM_PRODUCT_CATALOG, 'ibexa_menu'))->setDesc('Product catalog'),
  243. (new Message(self::ITEM_PRODUCT_CATALOG_PRODUCTS, 'ibexa_menu'))->setDesc('Products'),
  244. (new Message(self::ITEM_PRODUCT_CATALOG_CATALOGS, 'ibexa_menu'))->setDesc('Catalogs'),
  245. (new Message(self::ITEM_PRODUCT_GROUP_SETTINGS, 'ibexa_menu'))->setDesc('Settings'),
  246. (new Message(self::ITEM_PRODUCT_CATALOG_PRODUCT_TYPES, 'ibexa_menu'))->setDesc('Product Types'),
  247. (new Message(self::ITEM_PRODUCT_CATALOG_ATTRIBUTE_GROUPS, 'ibexa_menu'))->setDesc('Attribute Groups'),
  248. (new Message(self::ITEM_PRODUCT_CATALOG_ATTRIBUTES, 'ibexa_menu'))->setDesc('Attributes'),
  249. (new Message(self::ITEM_PRODUCT_CATALOG_CUSTOMER_GROUPS, 'ibexa_menu'))->setDesc('Customer Groups'),
  250. (new Message(self::ITEM_PRODUCT_CATALOG_CURRENCIES, 'ibexa_menu'))->setDesc('Currencies'),
  251. (new Message(self::ITEM_COMMERCE, 'ibexa_menu'))->setDesc('Commerce'),
  252. (new Message(self::ITEM_PRODUCT_CATALOG_CATEGORIES, 'ibexa_menu'))->setDesc('Categories'),
  253. ];
  254. }
  255. private function addCommerceMenu(ItemInterface $menu): void
  256. {
  257. if (!$this->isCommerceEnabled()) {
  258. return;
  259. }
  260. $menu->addChild(
  261. self::ITEM_COMMERCE,
  262. [
  263. 'attributes' => [
  264. 'data-tooltip-placement' => 'right',
  265. 'data-tooltip-extra-class' => 'ibexa-tooltip--navigation',
  266. ],
  267. 'extras' => [
  268. 'icon' => 'cart-full',
  269. 'orderNumber' => 100,
  270. ],
  271. ]
  272. );
  273. }
  274. private function canViewProducts(): bool
  275. {
  276. return $this->permissionResolver->canUser(new ViewProduct());
  277. }
  278. private function canViewCustomerGroups(): bool
  279. {
  280. return $this->permissionResolver->canUser(new ViewCustomerGroup());
  281. }
  282. private function canViewProductTypes(): bool
  283. {
  284. return $this->permissionResolver->canUser(new ViewProductType());
  285. }
  286. private function canAdministrateCurrencies(): bool
  287. {
  288. return $this->permissionResolver->canUser(new AdministrateCurrencies());
  289. }
  290. private function getProductCatalogRoutePattern(): string
  291. {
  292. return $this->isCommerceEnabled() ?
  293. '~^ibexa\.product_catalog\.(?!(customer_group|currency))~' :
  294. '~^ibexa\.product_catalog\.~';
  295. }
  296. private function isCommerceEnabled(): bool
  297. {
  298. return $this->commerceSiteConfig !== null && $this->commerceSiteConfig->isCommerceEnabled();
  299. }
  300. }