src/App/Controller/Web/AbstractWebController.php line 104

Open in your IDE?
  1. <?php
  2. namespace App\Controller\Web;
  3. use App\Component\Renderer\RenderContext;
  4. use App\Component\ViewLayer\Views\WebDocView;
  5. use App\Controller\AbstractController;
  6. use App\Entity\Content\Common\Props\SlugInterface;
  7. use App\Util\Ulids;
  8. use Cms\ContainerBundle\Entity\Container;
  9. use Cms\CoreBundle\Model\Scenes\DashboardScenes\DocumentScene;
  10. use Cms\CoreBundle\Service\SceneRenderer;
  11. use Cms\DomainBundle\Entity\Domain;
  12. use Cms\FrontendBundle\Exception\FrontendBuilderException;
  13. use Cms\FrontendBundle\Service\FrontendBuilder;
  14. use Cms\FrontendBundle\Service\ResolverManager;
  15. use Cms\ThemeBundle\Service\PackageManager;
  16. use Symfony\Component\HttpFoundation\RedirectResponse;
  17. use Symfony\Component\HttpFoundation\Request;
  18. use Symfony\Component\HttpFoundation\Response;
  19. use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
  20. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  21. /**
  22.  *
  23.  */
  24. abstract class AbstractWebController extends AbstractController
  25. {
  26.     /**
  27.      * @param string|Request|null $input
  28.      * @return Domain
  29.      */
  30.     protected function determineDomain($input null): Domain
  31.     {
  32.         switch (true) {
  33.             case is_string($input):
  34.                 $host $input;
  35.                 break;
  36.             case empty($input):
  37.                 $host $this->getRequest()->getHost();
  38.                 break;
  39.             case $input instanceof Request:
  40.                 $host $input->getHost();
  41.                 break;
  42.             default:
  43.                 throw new \LogicException();
  44.         }
  45.         $domain $this->getResolverManager()->getDomainResolver()->resolveDomainByHostname(
  46.             $host
  47.         );
  48.         if ( ! $domain) {
  49.             throw new NotFoundHttpException();
  50.         }
  51.         return $domain;
  52.     }
  53.     /**
  54.      * @param string|null $home
  55.      * @return Container
  56.      */
  57.     abstract protected function determineSite(?string $home null): Container;
  58.     /**
  59.      * @param Container $root
  60.      * @param string|Container|null $path
  61.      * @return Container
  62.      */
  63.     protected function determineDepartment(Container $root$path): Container
  64.     {
  65.         switch (true) {
  66.             case $path instanceof Container:
  67.                 $department $this->getResolverManager()->getDepartmentResolver()->resolveRootByDepartment($path);
  68.                 break;
  69.             default:
  70.                 $department $this->getResolverManager()->getDepartmentResolver()->resolveDepartmentByPath(
  71.                     $root,
  72.                     $path
  73.                 );
  74.         }
  75.         if ( ! $department instanceof Container) {
  76.             throw new NotFoundHttpException();
  77.         }
  78.         return $department;
  79.     }
  80.     /**
  81.      * @param Container $department
  82.      * @return array
  83.      */
  84.     protected function determineAncestry(Container $department): array
  85.     {
  86.         return $this->getResolverManager()->getDepartmentResolver()->resolveFurthestAncestorsWithDepartment(
  87.             $department
  88.         );
  89.     }
  90.     /**
  91.      * @param Request|null $request
  92.      * @return RenderContext
  93.      */
  94.     public function contextualize(?Request $request null): RenderContext
  95.     {
  96.         if ( ! $request) {
  97.             $request $this->getRequest();
  98.         }
  99.         $params $request->attributes->get('_route_params');
  100.         if ( ! $params['host']) {
  101.             throw new \RuntimeException();
  102.         }
  103.         return $this->generateRenderContext(
  104.             $domain $this->determineDomain($params['host']),
  105.             $this->determineDepartment(
  106.                 $this->determineSite($domain),
  107.                 $params['path'] ?? null,
  108.             ),
  109.         );
  110.     }
  111.     /**
  112.      * @param Domain $domain
  113.      * @param Container $department
  114.      * @return RenderContext
  115.      */
  116.     public function generateRenderContext(
  117.         Domain $domain,
  118.         Container $department
  119.     ): RenderContext
  120.     {
  121.         return new RenderContext(
  122.             $this->getRequest(),
  123.             $this->getEnvironment(),
  124.             $this->getParameter('dashboard.hostname'),
  125.             $domain->getTenant(),
  126.             $domain,
  127.             $this->determineAncestry($department),
  128.             $this->getResolverManager()->getSchoolResolver()->resolveSchoolByDepartment(
  129.                 $department
  130.             ),
  131.             $theme $this->getResolverManager()->getThemeResolver()->resolveThemeByDepartment(
  132.                 $department
  133.             ),
  134.             $this->getPackageManager()->getPackageForTheme(
  135.                 $theme
  136.             ),
  137.             $this->getResolverManager()->getOuterLayoutResolver()->resolveOuterLayoutByDepartment(
  138.                 $department
  139.             ),
  140.             $this->getResolverManager()->getInnerLayoutResolver()->resolveInnerLayoutByDepartment(
  141.                 $department
  142.             )
  143.         );
  144.     }
  145.     /**
  146.      * @param Request|null $request
  147.      * @return Response
  148.      * @throws FrontendBuilderException
  149.      */
  150.     protected function legacy(?Request $request null): Response
  151.     {
  152.         // default request if not given
  153.         if ( ! $request) {
  154.             $request $this->getRequest();
  155.         }
  156.         // close the session as it isn't needed on the frontend
  157.         $this->closeSession();
  158.         try {
  159.             $response $this->getFrontendBuilder()->build($request);
  160.         } catch (FrontendBuilderException $e) {
  161.             $response = new Response(
  162.                 $this->getSceneRenderer()->render(new DocumentScene(
  163.                     '@CmsCore/setup/default.html.twig',
  164.                     array(
  165.                         'key' => array_flip(
  166.                             (new \ReflectionClass(FrontendBuilderException::class))->getConstants()
  167.                         )[$e->getCode()],
  168.                         'message' => $e->getMessage(),
  169.                     )
  170.                 )),
  171.                 500,
  172.                 []
  173.             );
  174.         } catch (BadRequestHttpException $e) {
  175.             $response = new Response(null400, []);
  176.         } catch (\Exception $e) {
  177.             throw $e;
  178.         }
  179.         return $response;
  180.     }
  181.     /**
  182.      * @param string $host
  183.      * @param string|null $home
  184.      * @param string|null $path
  185.      * @return WebDocView
  186.      */
  187.     protected function actionLanding(
  188.         string $host,
  189.         ?string $home null,
  190.         ?string $path null
  191.     ): WebDocView
  192.     {
  193.         // generate context from the stuff we assembled
  194.         $context $this->generateRenderContext(
  195.             $this->determineDomain($host),
  196.             $this->determineDepartment(
  197.                 $this->determineSite($home),
  198.                 $path
  199.             )
  200.         );
  201.         // set title for page
  202.         $context->getDom()->getTitle()
  203.             ->setTitle('Feed')
  204.             ->setSection($context->getDepartment()->getName())
  205.             ->setProduct(null)
  206.             ->setBrand($context->getTenant()->getName());
  207.         // get feed entries
  208.         $results = [];
  209.         return (new WebDocView([
  210.             'vars' => $context,
  211.             'results' => $results,
  212.         ]))->setRenderContext($context);
  213.     }
  214.     /**
  215.      * @return ResolverManager|object
  216.      */
  217.     protected function getResolverManager(): ResolverManager
  218.     {
  219.         return $this->get(__METHOD__);
  220.     }
  221.     /**
  222.      * @return PackageManager|object
  223.      */
  224.     protected function getPackageManager(): PackageManager
  225.     {
  226.         return $this->get(__METHOD__);
  227.     }
  228.     /**
  229.      * @return FrontendBuilder|object
  230.      */
  231.     protected function getFrontendBuilder(): FrontendBuilder
  232.     {
  233.         return $this->get(__METHOD__);
  234.     }
  235.     /**
  236.      * @return SceneRenderer|object
  237.      */
  238.     protected function getSceneRenderer(): SceneRenderer
  239.     {
  240.         return $this->get(__METHOD__);
  241.     }
  242.     /**
  243.      * Helper to deal with accepting URLs to old migrated content that aren't using the new ID patterns.
  244.      *
  245.      * @param string $class
  246.      * @param string $id
  247.      * @param string $route
  248.      * @param array $params
  249.      * @return RedirectResponse|null
  250.      */
  251.     protected function handleMigratedContent(
  252.         string $class,
  253.         string $id,
  254.         string $route,
  255.         array $params = []
  256.     ): ?RedirectResponse
  257.     {
  258.         // if the id is an integer pattern, handle seeing if it is a migrated piece of content
  259.         if (is_numeric($id)) {
  260.             // attempt to load the content by this old id
  261.             $object $this->getEntityManager()->getRepository($class)->findOneBy([
  262.                 'migrationId' => (int) $id,
  263.             ]);
  264.             // if something was found, we want to redirect it to the proper url
  265.             if ($object) {
  266.                 // the redirection should fix the id and ensure the proper slug
  267.                 return $this->redirectToRoute(
  268.                     $route,
  269.                     array_merge(
  270.                         $params,
  271.                         [
  272.                             'id' => $object->getId(),
  273.                             'slug' => ($object instanceof SlugInterface) ? $object->getSlug() : null,
  274.                         ],
  275.                     ),
  276.                 );
  277.             }
  278.         }
  279.         return null;
  280.     }
  281.     /**
  282.      * Helper to deal with accepting URLs to content that aren't using the correct slug.
  283.      *
  284.      * @param string $class
  285.      * @param string $id
  286.      * @param string $slug
  287.      * @param string $route
  288.      * @param array $params
  289.      * @return RedirectResponse|null
  290.      */
  291.     protected function handleIncorrectSlug(
  292.         string $class,
  293.         string $id,
  294.         string $slug,
  295.         string $route,
  296.         array $params = []
  297.     ): ?RedirectResponse
  298.     {
  299.         // if the id is not ulid pattern, we need to skip all of this
  300.         if ( ! Ulids::test($id)) {
  301.             return null;
  302.         }
  303.         // attempt to load the content by the id
  304.         $object $this->getEntityManager()->getRepository($class)->find($id);
  305.         // if something was found and the slug is not correct, we need to redirect
  306.         if ($object instanceof SlugInterface && $object->getSlug() !== $slug) {
  307.             // the redirection should fix the id and ensure the proper slug
  308.             return $this->redirectToRoute(
  309.                 $route,
  310.                 array_merge(
  311.                     $params,
  312.                     [
  313.                         'slug' => $object->getSlug(),
  314.                     ],
  315.                 ),
  316.             );
  317.         }
  318.         return null;
  319.     }
  320. }