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

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