src/App/Service/Content/WebUrlGenerator.php line 277

Open in your IDE?
  1. <?php
  2. namespace App\Service\Content;
  3. use App\Entity\Content\AbstractObject;
  4. use App\Entity\Content\Common\Props\LinkInterface;
  5. use App\Entity\Content\Common\Props\SlugInterface;
  6. use App\Entity\Content\Events\Event\EventObject;
  7. use App\Entity\Content\Exhibits\Video\VideoObject;
  8. use App\Entity\Content\Posts\Post\PostObject;
  9. use App\Entity\Feed\AbstractEntry;
  10. use App\Entity\Feed\Entry\AbstractContentEntry;
  11. use App\Entity\Feed\Entry\ContentVideoEntry;
  12. use App\Model\Content\Media\AbstractMedia;
  13. use App\Service\MediaDecorator;
  14. use Cms\ContainerBundle\Entity\Container;
  15. use Cms\ContainerBundle\Entity\Containers\GenericContainer;
  16. use Cms\ContainerBundle\Entity\Containers\IntranetContainer;
  17. use Cms\ContainerBundle\Entity\Containers\PersonalContainer;
  18. use Cms\FrontendBundle\Service\ResolverManager;
  19. use Cms\ModuleBundle\Entity\Proxy;
  20. use Cms\ModuleBundle\Model\ModuleConfig;
  21. use Cms\Modules\PageBundle\Entity\Page\PageProxy;
  22. use Spatie\Url\Url;
  23. use Symfony\Component\HttpFoundation\Request;
  24. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  25. use Symfony\Component\Routing\RouterInterface;
  26. use Laminas\Uri\Uri;
  27. /**
  28.  *
  29.  */
  30. final class WebUrlGenerator
  31. {
  32.     // DI
  33.     protected RouterInterface $router;
  34.     protected ResolverManager $resolver;
  35.     protected MediaDecorator $decorator;
  36.     /**
  37.      * @param RouterInterface $router
  38.      * @param ResolverManager $resolver
  39.      * @param MediaDecorator $decorator
  40.      */
  41.     public function __construct(
  42.         RouterInterface $router,
  43.         ResolverManager $resolver,
  44.         MediaDecorator $decorator
  45.     )
  46.     {
  47.         $this->router $router;
  48.         $this->resolver $resolver;
  49.         $this->decorator $decorator;
  50.     }
  51.     /**
  52.      * @param Container $department
  53.      * @param string|null $path
  54.      * @return Url|null
  55.      */
  56.     public function catchall(Container $department, ?string $path null): ?Url
  57.     {
  58.         // need to chunk up the path as well
  59.         $path $path Url::fromString(urldecode($path)) : null;
  60.         // get the root department for the object
  61.         $root $this->resolver->getDepartmentResolver()->resolveRootByDepartment(
  62.             $department
  63.         );
  64.         // generate the route name we are looking for
  65.         $route sprintf(
  66.             'app.web.%s.default.catchall.%s',
  67.             $root::ROUTING_SLUG,
  68.             (($root->getId() === $department->getId()) && ! $path) ? 'root' 'sub'
  69.         );
  70.         // setup params
  71.         $params array_merge(
  72.             [
  73.                 'host' => $this->resolver->getUrlResolver()->resolveHostForDepartment(
  74.                     $department
  75.                 ),
  76.             ],
  77.             (($root->getId() !== $department->getId()) || $path) ? [
  78.                 'path' => trim((rtrim($this->resolver->getUrlResolver()->resolvePathForDepartment(
  79.                     $department
  80.                 ), '/') . '/' ltrim($path->getPath(), '/')), '/'),
  81.             ] : [],
  82.             ($root instanceof PersonalContainer) ? [
  83.                 'home' => $root->getAccount()->getEmail(),
  84.             ] : [],
  85.         );
  86.         // get the raw string url
  87.         $url $this->router->generate(
  88.             $route,
  89.             $params,
  90.             UrlGeneratorInterface::ABSOLUTE_URL
  91.         );
  92.         // convert to a more usable object
  93.         // set things like host and scheme
  94.         $url Url::fromString($url)
  95.             ->withScheme($this->resolver->getUrlResolver()->resolveSchemeForDepartment(
  96.                 $department
  97.             ))
  98.             ->withHost($this->resolver->getUrlResolver()->resolveHostForDepartment(
  99.                 $department
  100.             ))
  101.         ;
  102.         if ($path) {
  103.             foreach ($path->getAllQueryParameters() as $key => $value) {
  104.                 $url $url->withQueryParameter($key$value);
  105.             }
  106.         }
  107.         return $url;
  108.     }
  109.     /**
  110.      * @param Container $department
  111.      * @param mixed|string|ModuleConfig $module
  112.      * @return Url|null
  113.      */
  114.     public function subscribe(Container $department$module): ?Url
  115.     {
  116.         // get the module key if using a module
  117.         // TODO: this is a hack for old cms practices...
  118.         if ($module instanceof ModuleConfig) {
  119.             $module $module->key();
  120.         }
  121.         // get the root department for the object
  122.         $root $this->resolver->getDepartmentResolver()->resolveRootByDepartment(
  123.             $department
  124.         );
  125.         // generate the route name we are looking for
  126.         $route sprintf(
  127.             'app.web.%s.%s.subscribe.%s',
  128.             $root::ROUTING_SLUG,
  129.             $module,
  130.             ($root->getId() === $department->getId()) ? 'root' 'sub'
  131.         );
  132.         // setup params
  133.         $params array_merge(
  134.             ($root instanceof GenericContainer) ? [
  135.                 'host' => $this->resolver->getUrlResolver()->resolveHostForDepartment(
  136.                     $department
  137.                 ),
  138.             ] : [],
  139.             ($root->getId() !== $department->getId()) ? [
  140.                 'path' => $this->resolver->getUrlResolver()->resolvePathForDepartment(
  141.                     $department
  142.                 ),
  143.             ] : []
  144.         );
  145.         // get the raw string url
  146.         $url $this->router->generate(
  147.             $route,
  148.             $params,
  149.             UrlGeneratorInterface::ABSOLUTE_URL
  150.         );
  151.         // convert to a more usable object
  152.         // set things like host and scheme
  153.         $url Url::fromString($url)
  154.             ->withScheme($this->resolver->getUrlResolver()->resolveSchemeForDepartment(
  155.                 $department
  156.             ))
  157.             ->withHost($this->resolver->getUrlResolver()->resolveHostForDepartment(
  158.                 $department
  159.             ))
  160.         ;
  161.         return $url;
  162.     }
  163.     /**
  164.      * @param Container $department
  165.      * @param mixed|string|ModuleConfig $module
  166.      * @return Url|null
  167.      */
  168.     public function landing(Container $department$module): ?Url
  169.     {
  170.         // get the module key if using a module
  171.         // TODO: this is a hack for old cms practices...
  172.         if ($module instanceof ModuleConfig) {
  173.             $module $module->key();
  174.         }
  175.         // get the root department for the object
  176.         $root $this->resolver->getDepartmentResolver()->resolveRootByDepartment(
  177.             $department
  178.         );
  179.         // generate the route name we are looking for
  180.         $route sprintf(
  181.             'app.web.%s.%s.landing.%s',
  182.             $root::ROUTING_SLUG,
  183.             $module,
  184.             ($root->getId() === $department->getId()) ? 'root' 'sub'
  185.         );
  186.         // setup params
  187.         $params array_merge(
  188.             ($root instanceof GenericContainer) ? [
  189.                 'host' => $this->resolver->getUrlResolver()->resolveHostForDepartment(
  190.                     $department
  191.                 ),
  192.             ] : [],
  193.             ($root->getId() !== $department->getId()) ? [
  194.                 'path' => $this->resolver->getUrlResolver()->resolvePathForDepartment(
  195.                     $department
  196.                 ),
  197.             ] : []
  198.         );
  199.         // get the raw string url
  200.         $url $this->router->generate(
  201.             $route,
  202.             $params,
  203.             UrlGeneratorInterface::ABSOLUTE_URL
  204.         );
  205.         // convert to a more usable object
  206.         // set things like host and scheme
  207.         $url Url::fromString($url)
  208.             ->withScheme($this->resolver->getUrlResolver()->resolveSchemeForDepartment(
  209.                 $department
  210.             ))
  211.             ->withHost($this->resolver->getUrlResolver()->resolveHostForDepartment(
  212.                 $department
  213.             ))
  214.         ;
  215.         return $url;
  216.     }
  217.     /**
  218.      * @param mixed $thing
  219.      * @param bool $final
  220.      * @return Url|null
  221.      */
  222.     public function view($thingbool $final false): ?Url
  223.     {
  224.         $related = ($thing instanceof AbstractObject) ? $thing null;
  225.         if ($thing instanceof AbstractContentEntry) {
  226.             $related $thing->getObject();
  227.         }
  228.         if ($final) {
  229.             switch (true) {
  230.                 case $related instanceof LinkInterface && $related->getLink():
  231.                     return ($related->isLinkInternal())
  232.                         ? $this->catchall($related->getDepartment(), $related->getLink())
  233.                         : $related->getLinkAsUrl();
  234.                 case $related instanceof VideoObject && $related->getFeature():
  235.                 case $related instanceof ContentVideoEntry && $related->getFeature():
  236.                     $this->decorator->urls($related->getFeature());
  237.                     return Url::fromString(
  238.                         $related->getFeature()->getDecorations()->get(AbstractMedia::DECORS__URLS)['direct'],
  239.                     );
  240.             }
  241.         }
  242.         switch (true) {
  243.             case $thing instanceof EventObject:
  244.             case $thing instanceof AbstractObject && $thing->isUnpublished():
  245.                 return null;
  246.             case $thing instanceof AbstractObject:
  247.                 return $this->generateAbstractObject($thing);
  248.             case $thing instanceof AbstractEntry:
  249.                 return $this->generateAbstractEntry($thing);
  250.             case $thing instanceof Proxy:
  251.                 return $this->generateProxy($thing);
  252.         }
  253.         throw new \LogicException();
  254.     }
  255.     /**
  256.      * @param Request $request
  257.      * @param array $query
  258.      * @return string
  259.      */
  260.     public function request(Request $request, array $query = []): string
  261.     {
  262.         $params array_filter(array_merge(
  263.             $request->query->all(),
  264.             $query,
  265.         ));
  266.         return (new Uri($request->getPathInfo()))->setQuery($params)->toString();
  267.     }
  268.     /**
  269.      * @param AbstractObject $object
  270.      * @return Url
  271.      */
  272.     protected function generateAbstractObject(AbstractObject $object): Url
  273.     {
  274.         // get the root department for the object
  275.         $root $this->resolver->getDepartmentResolver()->resolveRootByDepartment(
  276.             $object->getDepartment()
  277.         );
  278.         // generate the route name we are looking for
  279.         $route sprintf(
  280.             'app.web.%s.%s.view.%s',
  281.             $root::ROUTING_SLUG,
  282.             $object::ROUTING_SLUG,
  283.             // TODO: need to create event for worker so that resolvers can clear cache on each iteration...
  284.             ($root->getId() === $object->getDepartment()->getId()) ? 'root' 'sub'
  285.         );
  286.         // setup params
  287.         $params array_merge(
  288.             [
  289.                 'host' => $this->resolver->getUrlResolver()->resolveHostForDepartment(
  290.                     $object->getDepartment()
  291.                 ),
  292.             ],
  293.             (($root->getId() !== $object->getDepartment()->getId())) ? [
  294.                 'path' => $path $this->resolver->getUrlResolver()->resolvePathForDepartment(
  295.                     $object->getDepartment()
  296.                 ),
  297.             ] : [],
  298.             ($root instanceof IntranetContainer) ? [
  299.                 'home' => $root->getSlug(),
  300.             ] : [],
  301.             ($root instanceof PersonalContainer) ? [
  302.                 'user' => $root->getAccount()->getEmail(),
  303.                 'home' => $root->getSlug(),
  304.             ] : [],
  305.             [
  306.                 'id' => $object->getId(),
  307.                 'slug' => ($object instanceof SlugInterface) ? $object->getSlug() : null,
  308.             ]
  309.         );
  310.         // get the raw string url
  311.         $url $this->router->generate(
  312.             $route,
  313.             $params,
  314.             UrlGeneratorInterface::ABSOLUTE_URL
  315.         );
  316.         // convert to a more usable object
  317.         // set things like host and scheme
  318.         $url Url::fromString($url)
  319.             ->withScheme($this->resolver->getUrlResolver()->resolveSchemeForDepartment(
  320.                 $object->getDepartment()
  321.             ))
  322.             ->withHost($this->resolver->getUrlResolver()->resolveHostForDepartment(
  323.                 $object->getDepartment()
  324.             ))
  325.         ;
  326.         return $url;
  327.     }
  328.     /**
  329.      * @param AbstractEntry $entry
  330.      * @return Url
  331.      */
  332.     protected function generateAbstractEntry(AbstractEntry $entry): Url
  333.     {
  334.         // get the root department for the object
  335.         $root $this->resolver->getDepartmentResolver()->resolveRootByDepartment(
  336.             $entry->getDepartment()
  337.         );
  338.         // generate the route name we are looking for
  339.         $route sprintf(
  340.             'app.web.%s.%s.view.%s',
  341.             $root::ROUTING_SLUG,
  342.             $entry::ROUTING_SLUG,
  343.             ($root->getId() === $entry->getDepartment()->getId()) ? 'root' 'sub'
  344.         );
  345.         // setup params
  346.         $params array_merge(
  347.             [
  348.                 'host' => $this->resolver->getUrlResolver()->resolveHostForDepartment(
  349.                     $entry->getDepartment()
  350.                 ),
  351.             ],
  352.             ($root->getId() !== $entry->getDepartment()->getId()) ? [
  353.                 'path' => $path $this->resolver->getUrlResolver()->resolvePathForDepartment(
  354.                     $entry->getDepartment()
  355.                 ),
  356.             ] : [],
  357.             ($root instanceof IntranetContainer) ? [
  358.                 'home' => $root->getSlug(),
  359.             ] : [],
  360.             ($root instanceof PersonalContainer) ? [
  361.                 'user' => $root->getAccount()->getEmail(),
  362.                 'home' => $root->getSlug(),
  363.             ] : [],
  364.             [
  365.                 'id' => $entry->getId(),
  366.                 'slug' => $entry->getSlug(),
  367.             ]
  368.         );
  369.         // get the raw string url
  370.         $url $this->router->generate(
  371.             $route,
  372.             $params,
  373.             UrlGeneratorInterface::ABSOLUTE_URL
  374.         );
  375.         // convert to a more usable object
  376.         // set things like host and scheme
  377.         $url Url::fromString($url)
  378.             ->withScheme($this->resolver->getUrlResolver()->resolveSchemeForDepartment(
  379.                 $entry->getDepartment()
  380.             ))
  381.             ->withHost($this->resolver->getUrlResolver()->resolveHostForDepartment(
  382.                 $entry->getDepartment()
  383.             ))
  384.         ;
  385.         return $url;
  386.     }
  387.     /**
  388.      * @param Proxy $object
  389.      * @return Url
  390.      */
  391.     protected function generateProxy(Proxy $object): Url
  392.     {
  393.         // get the root department for the object
  394.         $root $this->resolver->getDepartmentResolver()->resolveRootByDepartment(
  395.             $object->getDepartment()
  396.         );
  397.         // generate the route name we are looking for
  398.         $route = ($object instanceof PageProxy)
  399.             ? sprintf(
  400.                 'app.web.%s.default.catchall.sub',// always generating a sub because there will always be a path
  401.                 $root::ROUTING_SLUG
  402.             )
  403.             : sprintf(
  404.                 'app.web.%s.%s.view.%s',
  405.                 $root::ROUTING_SLUG,
  406.                 $object::ROUTING_SLUG,
  407.                 ($root->getId() === $object->getDepartment()->getId()) ? 'root' 'sub'
  408.             )
  409.         ;
  410.         // setup params
  411.         $path null;
  412.         $params array_merge(
  413.             [
  414.                 'host' => $this->resolver->getUrlResolver()->resolveHostForDepartment(
  415.                     $object->getDepartment()
  416.                 ),
  417.             ],
  418.             ($root->getId() !== $object->getDepartment()->getId()) ? [
  419.                 'path' => $path $this->resolver->getUrlResolver()->resolvePathForDepartment(
  420.                     $object->getDepartment()
  421.                 ),
  422.             ] : [],
  423.             ($root instanceof IntranetContainer) ? [
  424.                 'home' => $root->getSlug(),
  425.             ] : [],
  426.             ($root instanceof PersonalContainer) ? [
  427.                 'user' => $root->getAccount()->getEmail(),
  428.                 'home' => $root->getSlug(),
  429.             ] : [],
  430.             ($object instanceof PageProxy)
  431.                 ? [
  432.                     'path' => implode('/'array_values(array_filter([
  433.                         trim($path'/'),
  434.                         $object->getData()->getSlug(),
  435.                     ]))),
  436.                 ]
  437.                 : [
  438.                     'id' => $object->getId(),
  439.                     'slug' => ($object instanceof SlugInterface) ? $object->getSlug() : null,
  440.                 ],
  441.         );
  442.         // get the raw string url
  443.         $url $this->router->generate(
  444.             $route,
  445.             $params,
  446.             UrlGeneratorInterface::ABSOLUTE_URL
  447.         );
  448.         // convert to a more usable object
  449.         // set things like host and scheme
  450.         $url Url::fromString($url)
  451.             ->withScheme($this->resolver->getUrlResolver()->resolveSchemeForDepartment(
  452.                 $object->getDepartment()
  453.             ))
  454.             ->withHost($this->resolver->getUrlResolver()->resolveHostForDepartment(
  455.                 $object->getDepartment()
  456.             ))
  457.         ;
  458.         return $url;
  459.     }
  460. }