vendor/boldr/cms-bundle/src/Controller/PermalinkController.php line 268

Open in your IDE?
  1. <?php
  2. namespace Boldr\Cms\CmsBundle\Controller;
  3. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  4. use Symfony\Component\HttpFoundation\{ RequestResponse };
  5. use Symfony\Component\Routing\Annotation\Route;
  6. use Symfony\Contracts\Cache\{ TagAwareCacheInterfaceItemInterface };
  7. use Psr\Cache\CacheItemPoolInterface;
  8. use Boldr\Cms\CmsBundle\Permalink\{ PermalinkHandlerInterfacePermalinkResolverInterfacePermalinkGeneratorInterfacePermalinkableInterface };
  9. use Symfony\Contracts\Translation\TranslatorInterface;
  10. use Psr\Container\ContainerInterface;
  11. class PermalinkController extends AbstractController
  12. {
  13.     /** @var TagAwareCacheInterface&CacheItemPoolInterface */
  14.     private TagAwareCacheInterface $cache;
  15.     private ContainerInterface $permalinkHandlers;
  16.     /** @var iterable<PermalinkResolverInterface> */
  17.     private iterable $permalinkResolvers;
  18.     private ContainerInterface $permalinkGenerators;
  19.     private ContainerInterface $permalinkableSerializers;
  20.     /**
  21.      * @param TagAwareCacheInterface&CacheItemPoolInterface $cache
  22.      * @param iterable<PermalinkResolverInterface> $permalinkResolvers
  23.      * @phpstan-ignore-next-line
  24.      */
  25.     public function __construct(TagAwareCacheInterface $cacheContainerInterface $permalinkHandlers,
  26.         ContainerInterface $permalinkGeneratorsiterable $permalinkResolversContainerInterface $permalinkableSerializers)
  27.     {
  28.         $this->cache $cache;
  29.         $this->permalinkHandlers $permalinkHandlers;
  30.         $this->permalinkGenerators $permalinkGenerators;
  31.         $this->permalinkResolvers $permalinkResolvers;
  32.         $this->permalinkableSerializers $permalinkableSerializers;
  33.     }
  34.     private function getPermalinkableClass(PermalinkableInterface $permalinkable): string
  35.     {
  36.         $permalinkableClass get_class($permalinkable);
  37.         if (substr($permalinkableClass015) == 'Proxies\__CG__\\')
  38.         {
  39.             $permalinkableClass substr($permalinkableClass15);
  40.         }
  41.         return $permalinkableClass;
  42.     }
  43.     /**
  44.      * Returns the permalinkable name and a serialize()able representation of a permalinkable.
  45.      *
  46.      * @see self::unserialize()
  47.      * @return null|array{0: string, 1: mixed} Array of
  48.      */
  49.     public function serialize(PermalinkableInterface $permalinkable)
  50.     {
  51.         $permalinkableClass $this->getPermalinkableClass($permalinkable);
  52.         if (!$this->permalinkableSerializers->has($permalinkableClass))
  53.         {
  54.             return null;
  55.         }
  56.         $serializer $this->permalinkableSerializers->get($permalinkableClass);
  57.         $serializable $serializer->serialize($permalinkable) ?? null;
  58.         return [$permalinkableClass$serializable];
  59.     }
  60.     /**
  61.      * Unserialized a serialized Permalinkable into a
  62.      */
  63.     public function unserialize(string $permalinkableClass$serialized): ?PermalinkableInterface
  64.     {
  65.         if (!$this->permalinkableSerializers->has($permalinkableClass))
  66.         {
  67.             return null;
  68.         }
  69.         // Convert the cached data into a Permalinkable object which can be handled by a PermalinkHandlerInterface.
  70.         $serializer $this->permalinkableSerializers->get($permalinkableClass);
  71.         $permalinkable $serializer->unserialize($permalinkableClass$serialized);
  72.         return $permalinkable;
  73.     }
  74.     private function _generate(PermalinkableInterface $permalinkablestring $locale)
  75.     {
  76.         // Find the permalink generator
  77.         $permalinkableClass $this->getPermalinkableClass($permalinkable);
  78.         $permalink $this->permalinkGenerators->has($permalinkableClass)
  79.             ? $this->permalinkGenerators->get($permalinkableClass)->generatePermalink($permalinkable$locale)
  80.             : null;
  81.         // If there is no permalink generator, or the permalink generator returns an empty link, return null
  82.         if ($permalink === '' || $permalink === null)
  83.         {
  84.             return null;
  85.         }
  86.         // If permalinks must be prefixed with the locale
  87.         if ($this->getParameter('boldr_cms.prefix_permalinks_with_locale'))
  88.         {
  89.             return $this->generateUrl('cms_permalink_localized', [
  90.                 'permalink' => $permalink,
  91.                 '_locale' => $locale
  92.             ]);
  93.         }
  94.         return $this->generateUrl('cms_permalink', [
  95.             'permalink' => $permalink
  96.         ]);
  97.     }
  98.     /**
  99.      * Generates a permalink URL for a permalinkable
  100.      *
  101.      * @param PermalinkableInterface $permalinkable
  102.      * @param string $locale
  103.      */
  104.     public function generate(PermalinkableInterface $permalinkablestring $locale): ?string
  105.     {
  106.         [$permalinkableClass$serializable] = $this->serialize($permalinkable);
  107.         if ($serializable === null)
  108.             return $this->_generate($permalinkable$locale);
  109.         $cacheKeyPrefix $this->getCacheKeyPrefix($permalinkableClass$serializable);
  110.         return $this->cache->get($cacheKeyPrefix.'.'.$locale, function($item) use ($permalinkable$locale$cacheKeyPrefix) {
  111.             $item->tag($cacheKeyPrefix);
  112.             return $this->_generate($permalinkable$locale);
  113.         });
  114.     }
  115.     /**
  116.      * Flush permainks
  117.      */
  118.     public function regeneratePermalink(PermalinkableInterface $permalinkable): void
  119.     {
  120.         [$permalinkableClass$serializable] = $this->serialize($permalinkable);
  121.         if ($serializable !== null)
  122.         {
  123.             $cacheKeyPrefix $this->getCacheKeyPrefix($permalinkableClass$serializable);
  124.             $this->cache->invalidateTags([$cacheKeyPrefix]);
  125.         }
  126.     }
  127.     private function getCacheKeyPrefix(string $permalinkableClass$representation)
  128.     {
  129.         $cacheKeyPrefix 'boldr_cms.permalinkable_permalinks.'$permalinkableClass .'.'serialize($representation);
  130.         $cacheKeyPrefix str_replace(['{''}''('')''/''\\''@'':''"'], '-'$cacheKeyPrefix);
  131.         return $cacheKeyPrefix;
  132.     }
  133.     /**
  134.      * @Route("/{permalink<.+>}", name="cms_permalink", priority=-1)
  135.      * @Route("/{_locale}/{permalink<.+>}", name="cms_permalink_localized", priority=-2)
  136.      */
  137.     public function resolve(Request $requestTranslatorInterface $translatorstring $permalinkbool $refresh false): Response
  138.     {
  139.         // Strip trailing slash
  140.         $permalink trim($permalink'/');
  141.         // If permalinks are prefixed with the locale, extract the locale and permalink identifier, and update the Request.
  142.         $prefixPermalinks $this->getParameter('boldr_cms.prefix_permalinks_with_locale');
  143.         if ($prefixPermalinks)
  144.         {
  145.             $permalinkParts explode('/'$permalink2);
  146.             if (count($permalinkParts) == 2)
  147.             {
  148.                 $locale $permalinkParts[0];
  149.                 $enabledLocales $this->getParameter('boldr_cms.enabled_locales');
  150.                 if (in_array($locale$enabledLocales))
  151.                 {
  152.                     $request->setLocale($locale);
  153.                     $translator->setLocale($locale);
  154.                     $this->container->get('router')->getContext()->setParameter('_locale'$locale);
  155.                     $permalink $permalinkParts[1];
  156.                 }
  157.             }
  158.         }
  159.         // Permalink resolution and caching
  160.         $permalinkable null;
  161.         // Search for information about this permalink in the cache, unless $refresh is true.
  162.         $cacheItem $this->cache->getItem($this->getPermalinkCacheKey($permalink$request->getLocale()));
  163.         if (!$refresh && $cacheItem->isHit())
  164.         {
  165.             [$permalinkableClass$serialized] = $cacheItem->get();
  166.             // If no cache manager exists for this permalinkable class, the cache must be out of date.
  167.             // Re-resolve the permalink.
  168.             if (!$this->permalinkableSerializers->has($permalinkableClass))
  169.             {
  170.                 return $this->resolve($request$translator$permalinktrue);
  171.             }
  172.             // Convert the cached data into a Permalinkable object which can be handled by a PermalinkHandlerInterface.
  173.             $serializer $this->permalinkableSerializers->get($permalinkableClass);
  174.             $permalinkable $serializer->unserialize($permalinkableClass$serialized);
  175.         }
  176.         else
  177.         {
  178.             // When no information about the permalink is found, query all permalink resolvers for a Permalinkable object that answers to this permalink.
  179.             $locale $request->getLocale();
  180.             foreach ($this->permalinkResolvers as $resolver)
  181.             {
  182.                 $permalinkable $resolver->resolvePermalink($permalink$locale);
  183.                 if ($permalinkable !== null)
  184.                 {
  185.                     // When a permalink was found, attempt to store the result in the permalink cache.
  186.                     $permalinkableClass $this->getPermalinkableClass($permalinkable);
  187.                     if ($this->permalinkableSerializers->has($permalinkableClass))
  188.                     {
  189.                         // If a cache manager exists for this type of Permalinkable, create a cache representation and store it in the cache.
  190.                         $serializer $this->permalinkableSerializers->get($permalinkableClass);
  191.                         $representation $serializer->serialize($permalinkable);
  192.                         $cacheItem->set([$permalinkableClass$representation]);
  193.                         $cacheKeyPrefix $this->getCacheKeyPrefix($permalinkableClass$representation);
  194.                         $cacheItem->tag($cacheKeyPrefix);
  195.                         $this->cache->save($cacheItem);
  196.                     }
  197.                     break;
  198.                 }
  199.             }
  200.         }
  201.         // If no Permalinkable object could be found for the permalink, show a not found page.
  202.         if ($permalinkable === null)
  203.             throw $this->createNotFoundException();
  204.         // Search for the appropriate PermalinkHandlerInterface for this Permalinkable.
  205.         $permalinkableClass $this->getPermalinkableClass($permalinkable);
  206.         if (!$this->permalinkHandlers->has($permalinkableClass))
  207.         {
  208.             if (!$refresh)
  209.             {
  210.                 // If no handler could be found, the cache is probably out of date. Re-resolve the permalink.
  211.                 return $this->resolve($request$translator$permalinktrue);
  212.             }
  213.             else
  214.             {
  215.                 // If ::resolve was already called with $refresh = true and still no correct handler was found, this means the permalink handler is misconfigured.
  216.                 throw new \Exception('No permalink handler for permalinkable of type '$permalinkableClass);
  217.             }
  218.         }
  219.         // Save the permalinkable in a request attribute
  220.         $request->attributes->set('_permalinkable'$permalinkable);
  221.         // Delegate handling the permalink to the responsible PermalinkHandlerInterface
  222.         $handler $this->permalinkHandlers->get($permalinkableClass);
  223.         return $handler->handlePermalink($permalinkable$request);
  224.     }
  225.     /**
  226.      * Gets a cache key for the permalink
  227.      */
  228.     private function getPermalinkCacheKey(string $permalinkstring $locale): string
  229.     {
  230.         return 'boldr_cms.permalink_permalinkables.'$locale .'.'.
  231.             str_replace(['{''}''('')','/','\\','@'':'], '_'str_replace('_''__'$permalink))
  232.         ;
  233.     }
  234. }