src/Controller/PageController.php line 70

  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\Article;
  4. use App\Entity\Category;
  5. use App\Entity\Form;
  6. use App\Entity\FormField;
  7. use App\Entity\Page;
  8. use App\Entity\Site;
  9. use App\Entity\SiteSection;
  10. use App\Service\SiteContentSvc;
  11. use Doctrine\Common\Collections\ArrayCollection;
  12. use Symfony\Component\HttpFoundation\Response;
  13. use Symfony\Component\Routing\Annotation\Route;
  14. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  15. use Doctrine\ORM\EntityManagerInterface;
  16. use Symfony\Component\HttpFoundation\Request;
  17. use Symfony\Component\HttpFoundation\RequestStack;
  18. use Symfony\Component\HttpKernel\Exception\HttpException;
  19. use Twig\Environment;
  20. /**
  21.  * Controller used to manage all page requests
  22.  */
  23. class PageController extends AbstractController {
  24.  protected $request;
  25.  protected $requestStack;
  26.  protected ?string $projectDir "";
  27.  protected ?string $publicDir "";
  28.  protected ?string $templatesDir "";
  29.  protected ?string $route "";
  30.  protected ?array $params = [];
  31.  protected ?EntityManagerInterface $em;
  32.  protected ?Environment $twig;
  33.  protected ?SiteContentSvc $contentSvc;
  34.  protected ?Site $site;
  35.  protected ?string $pronoun;
  36.  protected ?string $timeframe;
  37.  protected ?string $newsletterTopMsg;
  38.  protected static array $states = ["AK" => "Alaska""AL" => "Alabama""AR" => "Arkansas""AZ" => "Arizona""CA" => "California""CO" => "Colorado""CT" => "Connecticut""DC" => "D.C.""DE" => "Delaware""FL" => "Florida""GA" => "Georgia""HI" => "Hawaii""IA" => "Iowa""ID" => "Idaho""IL" => "Illinois""IN" => "Indiana""KS" => "Kansas""KY" => "Kentucky""LA" => "Louisiana""MA" => "Massachusetts""MD" => "Maryland""ME" => "Maine""MI" => "Michigan""MN" => "Minnesota""MO" => "Missouri""MS" => "Mississippi""MT" => "Montana""NC" => "N. Carolina""ND" => "N. Dakota""NE" => "Nebraska""NH" => "New Hampshire""NJ" => "New Jersey""NM" => "New Mexico""NV" => "Nevada""NY" => "New York""OH" => "Ohio""OK" => "Oklahoma""OR" => "Oregon""PA" => "Pennsylvania""PR" => "Puerto Rico""RI" => "Rhode Island""SC" => "S. Carolina""SD" => "S. Dakota""TN" => "Tennessee""TX" => "Texas""UT" => "Utah""VA" => "Virginia""VI" => "Virgin Islands""VT" => "Vermont""WA" => "Washington""WI" => "Wisconsin""WV" => "W. Virginia""WY" => "Wyoming"];
  39.  public function __construct(RequestStack $requestStackEntityManagerInterface $emEnvironment $twigSiteContentSvc $contentSvc) {
  40.   $this->em $em;
  41.   $this->twig $twig;
  42.   $this->contentSvc $contentSvc;
  43.   $this->requestStack $requestStack;
  44.   $this->request $requestStack->getCurrentRequest();
  45.   $this->route $this->request->attributes->get("_route");
  46.   $this->params $this->request->attributes->get("_route_params");
  47.   $this->templatesDir preg_replace("/public/""templates"getcwd());
  48.   if (!empty($_ENV["SITE_ID"])) {
  49.    $this->site $em->getRepository(Site::class)->find(["siteId" => $_ENV["SITE_ID"]]);
  50.    $this->contentSvc->setSite($this->site);
  51.   }
  52.   $this->pronoun = (!empty($_ENV["PRONOUN"])) ? $_ENV["PRONOUN"] : null;
  53.   $this->timeframe = (!empty($_ENV["TIMEFRAME"])) ? $_ENV["TIMEFRAME"] : "monthly";
  54.   $this->newsletterTopMsg = (!empty($_ENV["NEWSLETTER_TOP_MSG"])) ? $_ENV["NEWSLETTER_TOP_MSG"] : null;
  55.  } // end function __construct
  56.  /**
  57.   * render index page
  58.   * @Route("/", name="index")
  59.   * @Route("/index.htm")
  60.   * @Route("/index")
  61.   */
  62.  public function index(Request $request) {
  63.   $pagePath "index";
  64.   if (!$this->isSiteSet()) return $this->pageNotFound();
  65.   // redirect requests to /index and /index.htm to /
  66.   if (str_contains($request->getPathInfo(), $pagePath)) return $this->redirect("/");
  67.   return new Response($this->contentSvc->getIndexTemplate()->render([
  68.    "page_title" => $this->contentSvc->getPageTitle($pagePath) ?? null,
  69.    "page_mkeys" => $this->contentSvc->getPageMkeys($pagePath) ?? null,
  70.    "page_mdesc" => $this->contentSvc->getPageMdesc($pagePath) ?? null,
  71.    "site" => $this->site,
  72.    "layout" => $this->site->getLayout(),
  73.    "content" => $this->contentSvc->getPageContent($pagePath) ?? null,
  74.   ]));
  75.  }
  76.  /**
  77.   * render a page
  78.   *
  79.   * @return Response
  80.   */
  81.  public function view(string $pagePathRequest $request) {
  82.   if (!$this->isSiteSet() || (!$this->contentSvc->hasPage($pagePath) && !$this->contentSvc->hasForm($pagePath))) return $this->pageNotFound($pagePath);
  83.   // if the requested path ends in .htm, do a 301 redirect to the same path without the .htm ending
  84.   if (str_contains($request->getPathInfo(), ".htm")) {
  85.    return $this->redirect(str_replace(".htm"""$request->getPathInfo()), Response::HTTP_MOVED_PERMANENTLY);
  86.   }
  87.   if ($this->contentSvc->hasForm($pagePath)) {
  88.    return $this->showForm($pagePath);
  89.   }
  90.   if ($this->contentSvc->hasPage($pagePath)) {
  91.    return $this->showPage($pagePath);
  92.   }
  93.   // if this point in the method has been reached, the page cannot be rendered
  94.   return $this->pageNotFound($pagePath);
  95.  }
  96.  /**
  97.   * render articles page
  98.   * @Route("/articles", name="articles")
  99.   * @Route("/articles.htm")
  100.   * @Route("/content_library.htm")
  101.   * @Route("/content-library", name="content-library")
  102.   */
  103.  public function articles(Request $request) {
  104.   if (!$this->isSiteSet()) return $this->pageNotFound();
  105.   // render a custom articles page, if one exists
  106.   if ($this->contentSvc->hasPage("articles")) {
  107.    return $this->showPage("articles");
  108.   }
  109.   // render the default articles page, shared between all sites
  110.   return new Response($this->contentSvc->getInnerTemplate()->render([
  111.    "site" => $this->site,
  112.    "layout" => $this->site->getLayout(),
  113.    "content" => $this->render("articles/articles.html.twig", [
  114.     "categories" => $this->em->getRepository(Category::class)->findBy(["parentId" => 'q4acvcqn'], ["categoryName" => "ASC"])
  115.    ])->getContent(),
  116.   ]));
  117.  }
  118.  /**
  119.   * render article category page
  120.   * @Route("/articles/{categorySlug}", name="article_category")
  121.   * @Route("/content-library/{categorySlug}", name="content-library-category")
  122.   */
  123.  public function articleCategory(string $categorySlugRequest $request) {
  124.   if (!$this->isSiteSet()) return $this->pageNotFound();
  125.   $categories = new ArrayCollection($this->em->getRepository(Category::class)->findBy(["parentId" => 'q4acvcqn'], ["categoryName" => "ASC"]));
  126.   $category $categories->filter(function($cat) use($categorySlug) {
  127.    return $cat->getSlug() == $categorySlug;
  128.   })->first();
  129.   $articles = new ArrayCollection($this->em->getRepository(Article::class)->findBy([], ["articleUpdated" => "DESC""articleTitle" => "ASC"]));
  130.   $articles $articles->filter(function($article) use($category) {
  131.    return $article->categories->contains($category);
  132.   });
  133.   if(!($category) instanceof Category) {
  134.    $this->addFlash("warning""Unable to find the requested category");
  135.    $this->redirectToRoute("articles");
  136.   }
  137.   // render the default article category page, shared between all sites
  138.   return new Response($this->contentSvc->getInnerTemplate()->render([
  139.    "site" => $this->site,
  140.    "layout" => $this->site->getLayout(),
  141.    "content" => $this->render("articles/category.html.twig", [
  142.     "category" => $category,
  143.     "articles" => $articles
  144.    ])->getContent(),
  145.   ]));
  146.  }
  147.  /**
  148.   * render individual article page
  149.   * @Route("/articles/{categorySlug}/{articleSlug}", name="article")
  150.   * @Route("/content-library/{categorySlug}/{articleSlug}", name="content-library-article")
  151.   */
  152.  public function article(string $categorySlugstring $articleSlugRequest $request) {
  153.   if (!$this->isSiteSet()) return $this->pageNotFound();
  154.   $categories = new ArrayCollection($this->em->getRepository(Category::class)->findBy(["parentId" => 'q4acvcqn'], ["categoryName" => "ASC"]));
  155.   $category $categories->filter(function($cat) use($categorySlug) {
  156.    return $cat->getSlug() == $categorySlug;
  157.   })->first();
  158.   $articles = new ArrayCollection($this->em->getRepository(Article::class)->findBy([], ["articleTitle" => "ASC"]));
  159.   $article $articles->filter(function($article) use($articleSlug) {
  160.    return $article->getSlug() == $articleSlug;
  161.   })->first();
  162.   if(!($article) instanceof Article) {
  163.    $this->addFlash("warning""Unable to find the requested article");
  164.    $this->redirectToRoute("articles");
  165.   }
  166.   // render the default article page, shared between all sites
  167.   return new Response($this->contentSvc->getInnerTemplate()->render([
  168.    "site" => $this->site,
  169.    "layout" => $this->site->getLayout(),
  170.    "content" => $this->render("articles/article.html.twig", [
  171.     "category" => $category,
  172.     "article" => $article
  173.    ])->getContent(),
  174.   ]));
  175.  }
  176.  /**
  177.   * render taxcenter page
  178.   * @Route("/taxcenter", name="taxcenter")
  179.   * @Route("/taxcenter.htm")
  180.   */
  181.  public function taxcenter(Request $request) {
  182.   if (!$this->isSiteSet()) return $this->pageNotFound();
  183.   // render a custom taxcenter page, if one exists
  184.   if ($this->contentSvc->hasPage("taxcenter")) {
  185.    return $this->showPage("taxcenter");
  186.   }
  187.   // render the default taxcenter page, shared between all sites
  188.   return new Response($this->contentSvc->getInnerTemplate()->render([
  189.    "site" => $this->site,
  190.    "layout" => $this->site->getLayout(),
  191.    "content" => $this->render("taxcenter/taxcenter.html.twig")->getContent(),
  192.   ]));
  193.  }
  194.  /**
  195.   * render taxcenter state refund page
  196.   * @Route("/state_refund", name="taxcenter_state_refund")
  197.   */
  198.  public function stateRefund(Request $request) {
  199.   if (!$this->isSiteSet()) return $this->pageNotFound();
  200.   return new Response($this->contentSvc->getInnerTemplate()->render([
  201.    "site" => $this->site,
  202.    "layout" => $this->site->getLayout(),
  203.    "content" => $this->render("taxcenter/state_refund.html.twig", [
  204.     "states" => self::$states
  205.    ])->getContent(),
  206.   ]));
  207.  }
  208.  /**
  209.   * render taxcenter state forms page
  210.   * @Route("/state_forms", name="taxcenter_state_forms")
  211.   */
  212.  public function stateForms(Request $request) {
  213.   if (!$this->isSiteSet()) return $this->pageNotFound();
  214.   return new Response($this->contentSvc->getInnerTemplate()->render([
  215.    "site" => $this->site,
  216.    "layout" => $this->site->getLayout(),
  217.    "content" => $this->render("taxcenter/state_forms.html.twig", [
  218.     "states" => self::$states
  219.    ])->getContent(),
  220.   ]));
  221.  }
  222.  /**
  223.   * render taxcenter calculators page
  224.   * @Route("/calculators", name="taxcenter_calculators")
  225.   */
  226.  public function calculators(Request $request) {
  227.   if (!$this->isSiteSet()) return $this->pageNotFound();
  228.   return new Response($this->contentSvc->getInnerTemplate()->render([
  229.    "site" => $this->site,
  230.    "layout" => $this->site->getLayout(),
  231.    "content" => $this->render("taxcenter/calculators.html.twig", [
  232.     "states" => self::$states
  233.    ])->getContent(),
  234.   ]));
  235.  }
  236.  /**
  237.   * render taxcenter retentionguide page
  238.   * @Route("/retentionguide", name="taxcenter_retentionguide")
  239.   */
  240.  public function retentionguide(Request $request) {
  241.   if (!$this->isSiteSet()) return $this->pageNotFound();
  242.   return new Response($this->contentSvc->getInnerTemplate()->render([
  243.    "site" => $this->site,
  244.    "layout" => $this->site->getLayout(),
  245.    "content" => $this->render("taxcenter/retentionguide.html.twig", [
  246.     "states" => self::$states
  247.    ])->getContent(),
  248.   ]));
  249.  }
  250.  /**
  251.   * render taxcenter subpage
  252.   * @Route("/taxcenter/{page}", name="taxcenter_page")
  253.   */
  254.  public function taxcenterPage(Request $requeststring $page) {
  255.   if (!$this->isSiteSet() || !file_exists($this->templatesDir "/taxcenter/{$page}.html.twig")) return $this->pageNotFound();
  256.   // render the default taxcenter subpage, shared between all sites
  257.   return new Response($this->contentSvc->getInnerTemplate()->render([
  258.    "site" => $this->site,
  259.    "layout" => $this->site->getLayout(),
  260.    "content" => $this->render("taxcenter/{$page}.html.twig", [
  261.     "states" => self::$states
  262.    ])->getContent(),
  263.   ]));
  264.  }
  265.  /**
  266.   * render contact page
  267.   * @Route("/contact", name="contact")
  268.   * @Route("/contact.htm")
  269.   */
  270.  public function contact(Request $request) {
  271.   if (!$this->isSiteSet()) return $this->pageNotFound();
  272.   // render a custom contact form, if one exists
  273.   if ($this->contentSvc->hasForm("contact")) {
  274.    return $this->showForm("contact");
  275.   }
  276.   // render a custom contact page, if one exists
  277.   if ($this->contentSvc->hasPage("contact")) {
  278.    return $this->showPage("contact");
  279.   }
  280.   // render the default contact page/form, shared between all sites
  281.   return new Response($this->contentSvc->getInnerTemplate()->render([
  282.    "site" => $this->site,
  283.    "layout" => $this->site->getLayout(),
  284.    "content" => $this->render("page/contact.html.twig", ["offices" => $this->site->getOffices(), "site" => $this->site"pronoun" => $this->pronoun])->getContent(),
  285.   ]));
  286.  }
  287.  /**
  288.   * render consultation page
  289.   * @Route("/consultation", name="consultation")
  290.   * @Route("/consultation.htm")
  291.   */
  292.  public function consultation(Request $request) {
  293.   if (!$this->isSiteSet()) return $this->pageNotFound();
  294.   // render a custom consultation form, if one exists
  295.   if ($this->contentSvc->hasForm("consultation")) {
  296.    return $this->showForm("consultation");
  297.   }
  298.   // render a custom consultation page, if one exists
  299.   if ($this->contentSvc->hasPage("consultation")) {
  300.    return $this->showPage("consultation");
  301.   }
  302.   // render the default consultation page/form, shared between all sites, OR a custom consultation form that submits to the default consultation form processing
  303.   if ($this->em->getRepository(Form::class)->findOneBy(["site" => $this->site"formConsultIntercept" => 1])) {
  304.    $form $this->em->getRepository(Form::class)->findOneBy(["site" => $this->site"formConsultIntercept" => 1]);
  305.    $formFields $this->em->getRepository(FormField::class)->findBy(["form" => $form], ["formFieldIndex" => "ASC"]);
  306.    return new Response($this->contentSvc->getInnerTemplate()->render([
  307.     "site" => $this->site,
  308.     "layout" => $this->site->getLayout(),
  309.     "content" => $this->render("page/customConsultation.html.twig", ["site" => $this->site"form" => $form"formFields" => $formFields])->getContent(),
  310.    ]));
  311.   } else {
  312.    return new Response($this->contentSvc->getInnerTemplate()->render([
  313.     "site" => $this->site,
  314.     "layout" => $this->site->getLayout(),
  315.     "content" => $this->render("page/consultation.html.twig", ["site" => $this->site])->getContent(),
  316.    ]));
  317.   }
  318.  }
  319.  /**
  320.   * render newsletter page
  321.   * @Route("/newsletter", name="newsletter")
  322.   * @Route("/newsletter.htm")
  323.   */
  324.  public function newsletter(Request $request) {
  325.   if (!$this->isSiteSet()) return $this->pageNotFound();
  326.   // render a custom newsletter form, if one exists
  327.   if ($this->contentSvc->hasForm("newsletter")) {
  328.    return $this->showForm("newsletter");
  329.   }
  330.   // render a custom newsletter page, if one exists
  331.   if ($this->contentSvc->hasPage("newsletter")) {
  332.    return $this->showPage("newsletter");
  333.   }
  334.   // render the default newsletter page/form, shared between all sites
  335.   return new Response($this->contentSvc->getInnerTemplate()->render([
  336.    "site" => $this->site,
  337.    "layout" => $this->site->getLayout(),
  338.    "content" => $this->render("page/newsletter.html.twig", ["site" => $this->site"pronoun" => $this->pronoun"timeframe" => $this->timeframe"newsletterTopMsg" =>  $this->newsletterTopMsg])->getContent(),
  339.   ]));
  340.  }
  341.  /**
  342.   * @Route("css/site_images/{file}", name= "site_get_image")
  343.   */
  344.  public function getImg(string $file): Response {
  345.   if (!$this->isSiteSet()) return $this->pageNotFound();
  346.   $imgFile getcwd() . "/site_images/" $file;
  347.   if (!file_exists($imgFile)) throw new HttpException("Image not found");
  348.   $mimeType mime_content_type($imgFile);
  349.   $response = new Response(file_get_contents($imgFile));
  350.   $response->headers->set('Content-Type'$mimeType);
  351.   return $response;
  352.  }
  353.  /**
  354.   * @Route("css/{cssFile}.css", name= "site_get_css", requirements={"cssFile"=".+"})
  355.   */
  356.  public function getCss(string $cssFile): Response {
  357.   if (!$this->isSiteSet()) return $this->pageNotFound();
  358.   $response = new Response();
  359.   $response->headers->set('Content-Type''text/css');
  360.   $response->setContent($this->contentSvc->getCssContent($cssFile));
  361.   return $response;
  362.  }
  363.  /**
  364.   * @Route("js/{jsFile}", name= "site_get_js", requirements={"jsFile"=".+"})
  365.   */
  366.  public function getJs(string $jsFile): Response {
  367.   if (!$this->isSiteSet()) return $this->pageNotFound();
  368.   $response = new Response();
  369.   $response->headers->set('Content-Type''text/js');
  370.   $response->setContent($this->contentSvc->getJsContent($jsFile));
  371.   return $response;
  372.  }
  373.  public function pageNotFound(?string $pagePath null): Response {
  374.   return new Response($this->contentSvc->getInnerTemplate()->render([
  375.    "page_title" => !empty($pagePath) && !empty($this->contentSvc->getPageTitle($pagePath)) ? $this->contentSvc->getPageTitle($pagePath) : "404 - Page Not Found | {$this->site->getSiteName()}",
  376.    "page_mkeys" => !empty($pagePath) &&  !empty($this->contentSvc->getPageMkeys($pagePath)) ? $this->contentSvc->getPageMkeys($pagePath) : null,
  377.    "page_mdesc" => !empty($pagePath) &&  !empty($this->contentSvc->getPageMdesc($pagePath)) ? $this->contentSvc->getPageMdesc($pagePath) : null,
  378.    "site" => $this->site,
  379.    "layout" => $this->site->getLayout(),
  380.    "content" => "<div id=\"notfound\" style=\"display: table; width: 100%; height: 100%; text-align: center; transition: all 0.6s;\">
  381.     <div class=\"missing\" style=\"display: table-cell; vertical-align: middle;\">
  382.      <h1 style=\"font-size: 50px; display: inline-block; padding-right: 12px; animation: type .5s alternate infinite;\">Error 404:</h1>
  383.      <h2>Page not found</h2>
  384.      <p>Looks like that page was removed, renamed, or does not exist.</p>
  385.      <h3><a href=\"/\">Click to Return Home</a></h3>
  386.     </div>
  387.    </div>"
  388.   ]));
  389.   //return $this->render("page/404.html.twig", ["pagePath" => $pagePath]);
  390.  }
  391.  protected function isSiteSet(): bool {
  392.   return $this->contentSvc->isSiteSet();
  393.  }
  394.  protected function showPage($pagePath): Response {
  395.   return new Response($this->contentSvc->getInnerTemplate()->render([
  396.    "page_title" => !empty($this->contentSvc->getPageTitle($pagePath)) ? $this->contentSvc->getPageTitle($pagePath) : "{$pagePath} | {$this->site->getSiteName()}",
  397.    "page_mkeys" => !empty($this->contentSvc->getPageMkeys($pagePath)) ? $this->contentSvc->getPageMkeys($pagePath) : null,
  398.    "page_mdesc" => !empty($this->contentSvc->getPageMdesc($pagePath)) ? $this->contentSvc->getPageMdesc($pagePath) : null,
  399.    "site" => $this->site,
  400.    "layout" => $this->site->getLayout(),
  401.    "content" => $this->contentSvc->getPageContent($pagePath)
  402.   ]));
  403.  }
  404.  protected function showForm($formPath): Response {
  405.   $form $this->contentSvc->getForm($formPath);
  406.   return new Response($this->contentSvc->getInnerTemplate()->render([
  407.    "site" => $this->site,
  408.    "layout" => $this->site->getLayout(),
  409.    "content" => $this->render("page/customForm.html.twig", ["site" => $this->site"form" => $form"formFields" => $form->getFormFields()])->getContent(),
  410.   ]));
  411.  }
  412. }