src/Controller/MarketingController.php line 256

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Blog;
  4. use App\Content;
  5. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  6. use Symfony\Component\HttpFoundation\Cookie;
  7. use Symfony\Component\HttpFoundation\RedirectResponse;
  8. use Symfony\Component\HttpFoundation\Request;
  9. use Symfony\Component\HttpFoundation\Response;
  10. use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
  11. use Symfony\Component\Routing\Annotation\Route;
  12. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  13. use Symfony\Component\Routing\RouterInterface;
  14. use Symfony\Contracts\Cache\CacheInterface;
  15. use Symfony\Contracts\Cache\ItemInterface;
  16. class MarketingController extends AbstractController
  17. {
  18.     /**
  19.      * List of the available customer logos for the landing page.
  20.      */
  21.     public static array $customerLogos = [
  22.         [
  23.             'img' => 'massmutual.png',
  24.             'name' => 'Mass Mutual',
  25.         ],
  26.         [
  27.             'img' => 'tmobile.png',
  28.             'name' => 'T-Mobile',
  29.         ],
  30.         [
  31.             'img' => 'boysgirlsclub.png',
  32.             'name' => 'Boys & Girls Club',
  33.         ],
  34.         [
  35.             'img' => 'convene.png',
  36.             'name' => 'Convene',
  37.         ],
  38.         [
  39.             'img' => 'reputation-nw.jpg',
  40.             'name' => 'Reputation.com',
  41.         ],
  42.         [
  43.             'img' => 'berkshirehathaway.png',
  44.             'name' => 'Berkshire Hathaway',
  45.         ],
  46.         [
  47.             'img' => 'gvr.png',
  48.             'name' => 'Gilbarco Veeder-Root',
  49.         ],
  50.         [
  51.             'img' => 'solutionreach.png',
  52.             'name' => 'SolutionReach',
  53.         ],
  54.         [
  55.             'img' => 'seniorly.png',
  56.             'name' => 'Seniorly',
  57.         ],
  58.         [
  59.             'img' => 'covetrus.png',
  60.             'name' => 'Covetrus',
  61.         ],
  62.         [
  63.             'img' => 'mutesix.png',
  64.             'name' => 'MuteSix',
  65.         ],
  66.         [
  67.             'img' => 'crispvideo.png',
  68.             'name' => 'Crisp Video',
  69.         ],
  70.     ];
  71.     /**
  72.      * List of the available customer logos for the healthcare page.
  73.      */
  74.     public static array $customerLogosHealthcare = [
  75.         [
  76.             'img' => 'axiom-lg.png',
  77.             'name' => 'Axiom Medical Consulting',
  78.         ],
  79.         [
  80.             'img' => 'SolutionReach logo.png',
  81.             'name' => 'SolutionReach',
  82.         ],
  83.         [
  84.             'img' => 'Metagenics logo.png',
  85.             'name' => 'Metagenics',
  86.         ],
  87.         [
  88.             'img' => 'Medicopy Logo.png',
  89.             'name' => 'Medicopy',
  90.         ],
  91.         [
  92.             'img' => 'Ambra Health Logo.png',
  93.             'name' => 'Ambra Health',
  94.         ],
  95.         [
  96.             'img' => 'Thyroid Virtual Clinic Logo.png',
  97.             'name' => 'Thyroid Virtual Clinic',
  98.         ],
  99.         [
  100.             'img' => 'Lifematters Logo.png',
  101.             'name' => 'Lifematters',
  102.         ],
  103.     ];
  104.     /**
  105.      * List of the available customer logos for the healthcare page.
  106.      */
  107.     public static array $customerLogosInsurance = [
  108.         [
  109.             'img' => 'ITM TwentyFirst Logo.png',
  110.             'name' => 'ITM TwentyFirst',
  111.         ],
  112.         [
  113.             'img' => 'Inshur Logo.png',
  114.             'name' => 'Inshur',
  115.         ],
  116.         [
  117.             'img' => 'Cypress Insurance Logo.png',
  118.             'name' => 'Cypress Insurance',
  119.         ],
  120.         [
  121.             'img' => 'ARGI Logo.png',
  122.             'name' => 'ARGI',
  123.         ],
  124.     ];
  125.     /**
  126.      * List of the available customer logos for the healthcare page.
  127.      */
  128.     public static array $customerLogosTech = [
  129.         [
  130.             'img' => 'uber.png',
  131.             'name' => 'Uber',
  132.         ],
  133.         [
  134.             'img' => 'Vonigo Logo.png',
  135.             'name' => 'Vonigo',
  136.         ],
  137.         [
  138.             'img' => 'Trimble Logo.png',
  139.             'name' => 'Trimble',
  140.         ],
  141.         [
  142.             'img' => 'Wisely Logo.png',
  143.             'name' => 'Wisely',
  144.         ],
  145.         [
  146.             'img' => 'chowly.png',
  147.             'name' => 'Chowly',
  148.         ],
  149.         [
  150.             'img' => 'e2open Logo.png',
  151.             'name' => 'e2open',
  152.         ],
  153.         [
  154.             'img' => 'Starmind Logo.png',
  155.             'name' => 'Starmind',
  156.         ],
  157.         [
  158.             'img' => 'Evercast Logo.png',
  159.             'name' => 'Evercast',
  160.         ],
  161.         [
  162.             'img' => 'Tempo Automation Logo.png',
  163.             'name' => 'Tempo Automation',
  164.         ],
  165.         [
  166.             'img' => 'Restream Logo.png',
  167.             'name' => 'Restream',
  168.         ],
  169.         [
  170.             'img' => 'Vidyard Logo.png',
  171.             'name' => 'Vidyard',
  172.         ],
  173.     ];
  174.     /**
  175.      * List of the available awards badges.
  176.      */
  177.     public static array $awardsBadges = [
  178.         [
  179.             'img' => 'capterra21.png',
  180.             'name' => 'Capterra',
  181.         ],
  182.         [
  183.             'img' => 'cloud-awards21.png',
  184.             'name' => 'Cloud Awards',
  185.         ],
  186.         [
  187.             'img' => 'cpa-choice21.png',
  188.             'name' => 'CPA Readers Choice',
  189.         ],
  190.         [
  191.             'img' => 'getapp21.png',
  192.             'name' => 'GetApp Category Leaders',
  193.         ],
  194.         [
  195.             'img' => 'leader-summer21.png',
  196.             'name' => 'Leader Summer 2021',
  197.         ],
  198.         [
  199.             'img' => 'sa-fr21.png',
  200.             'name' => 'Software Advice Front Runners',
  201.         ],
  202.         [
  203.             'img' => 'saasworthy21.png',
  204.             'name' => 'SaasWorty Top 20',
  205.         ],
  206.         [
  207.             'img' => 'corpvis21.jpg',
  208.             'name' => 'Corporate Vision Excellence Award',
  209.         ],
  210.         [
  211.             'img' => 'i5k.png',
  212.             'name' => 'Inc. 5000',
  213.         ],
  214.         [
  215.             'img' => 'forbes21.png',
  216.             'name' => 'Forbes Official Member',
  217.         ],
  218.     ];
  219.     /**
  220.      * Mapping of the feature page redirects.
  221.      *   Old -> New.
  222.      */
  223.     private const FEATURE_REDIRECTS = [
  224.         'invoicing' => 'invoice-to-cash',
  225.         'subscription-billing' => 'subscription-billing',
  226.         'payments' => 'payment-plans',
  227.         'billing-portal' => 'customer-portal',
  228.     ];
  229.     #[Route(path'/login'name'login_redirect'methods: ['GET'])]
  230.     public function loginRedirect(): Response
  231.     {
  232.         return new RedirectResponse($this->getParameter('app.dashboard_url'));
  233.     }
  234.     #[Route(path'/signup'name'signup_redirect'methods: ['GET'])]
  235.     public function signupRedirect(Request $request): Response
  236.     {
  237.         $url 'https://invoiced.com/signup';
  238.         if ($query $request->query->all()) {
  239.             $url .= '?'.http_build_query($query);
  240.         }
  241.         return new RedirectResponse($url);
  242.     }
  243.     #[Route(path'/'name'landing'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => 1'sitemap_changefreq' => 'daily'])]
  244.     public function index(Blog $blog): Response
  245.     {
  246.         return $this->render('landing.twig', [
  247.             'logos' => $this->getCustomerLogos(),
  248.             'latestBlogPosts' => $blog->getPosts(2),
  249.             'badges' => $this->getAwardsBadges(),
  250.         ]);
  251.     }
  252.     private function getCustomerLogos(): array
  253.     {
  254.         $logos self::$customerLogos;
  255.         $logos array_slice($logos012);
  256.         foreach ($logos as &$logo) {
  257.             $logo['img'] = '/img/landing2/customer-logos/'.$logo['img'];
  258.         }
  259.         return $logos;
  260.     }
  261.     private function getAwardsBadges(): array
  262.     {
  263.         $badges self::$awardsBadges;
  264.         $badges array_slice($badges010);
  265.         foreach ($badges as &$badge) {
  266.             $badge['img'] = '/img/badges/'.$badge['img'];
  267.         }
  268.         return $badges;
  269.     }
  270.     #[Route(path'/features'name'shortcut_features'methods: ['GET'])]
  271.     public function shortcutFeatures(): Response
  272.     {
  273.         return new RedirectResponse('/product'301);
  274.     }
  275.     #[Route(path'/features/{section}'name'shortcut_features_section'methods: ['GET'])]
  276.     public function shortcutFeaturesSection($section): Response
  277.     {
  278.         if (isset(self::FEATURE_REDIRECTS[$section])) {
  279.             return new RedirectResponse('/product/'.self::FEATURE_REDIRECTS[$section], 301);
  280.         }
  281.         return new RedirectResponse('/product'301);
  282.     }
  283.     #[Route(path'/product'name'product'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => 1'sitemap_changefreq' => 'weekly'])]
  284.     public function product(): Response
  285.     {
  286.         return $this->render('product/product.twig', [
  287.             'logos' => $this->getCustomerLogos(),
  288.             'badges' => $this->getAwardsBadges(),
  289.         ]);
  290.     }
  291.     #[Route(path'/product/cash-application'name'product_cash_application'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'weekly'])]
  292.     public function productCashApplication(): Response
  293.     {
  294.         return $this->render('features/cash-application.twig', [
  295.             'logos' => $this->getCustomerLogos(),
  296.             'badges' => $this->getAwardsBadges(),
  297.         ]);
  298.     }
  299.     #[Route(path'/product/customer-portal'name'product_customer_portal'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'weekly'])]
  300.     public function productCustomerPortal(): Response
  301.     {
  302.         return $this->render('features/customer-portal.twig', [
  303.             'logos' => $this->getCustomerLogos(),
  304.             'badges' => $this->getAwardsBadges(),
  305.         ]);
  306.     }
  307.     #[Route(path'/product/erp-connect'name'product_erp_connect'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'weekly'])]
  308.     public function productErpConnect(): Response
  309.     {
  310.         return $this->render('features/erp-connect.twig');
  311.     }
  312.     #[Route(path'/product/estimates'name'product_estimates'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'weekly'])]
  313.     public function productEstimates(): Response
  314.     {
  315.         return $this->render('features/estimates.twig', [
  316.             'logos' => $this->getCustomerLogos(),
  317.             'badges' => $this->getAwardsBadges(),
  318.         ]);
  319.     }
  320.     #[Route(path'/gateways'name'shortcut_payment_gateways'methods: ['GET'])]
  321.     public function shortcutPaymentGateways(): Response
  322.     {
  323.         return new RedirectResponse('/product/integrations#payment-gateways'301);
  324.     }
  325.     #[Route(path'/integrations'name'shortcut_integrations'methods: ['GET'])]
  326.     public function shortcutIntegrations(): Response
  327.     {
  328.         return new RedirectResponse('/product/integrations'301);
  329.     }
  330.     #[Route(path'/product/integrations'name'product_integrations'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'weekly'])]
  331.     public function integrations(): Response
  332.     {
  333.         return $this->render('features/integrations.twig');
  334.     }
  335.     #[Route(path'/product/invoice-to-cash'name'product_invoice_to_cash'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'weekly'])]
  336.     public function productInvoiceToCash(): Response
  337.     {
  338.         return $this->render('features/invoice-to-cash.twig', [
  339.             'logos' => $this->getCustomerLogos(),
  340.             'badges' => $this->getAwardsBadges(),
  341.         ]);
  342.     }
  343.     #[Route(path'/product/payment-plans'name'product_payment_plans'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'weekly'])]
  344.     public function productPaymentPlans(): Response
  345.     {
  346.         return $this->render('features/payment-plans.twig', [
  347.             'logos' => $this->getCustomerLogos(),
  348.             'badges' => $this->getAwardsBadges(),
  349.         ]);
  350.     }
  351.     #[Route(path'/security'name'shortcut_security'methods: ['GET'])]
  352.     public function shortcutSecurity(): Response
  353.     {
  354.         return new RedirectResponse('/product/security'301);
  355.     }
  356.     #[Route(path'/product/security'name'security'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.5''sitemap_changefreq' => 'monthly'])]
  357.     public function security(): Response
  358.     {
  359.         return $this->render('security.twig');
  360.     }
  361.     #[Route(path'/product/subscription-billing'name'product_subscription_billing'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'weekly'])]
  362.     public function productSubscriptionBilling(): Response
  363.     {
  364.         return $this->render('features/subscription-billing.twig', [
  365.             'logos' => $this->getCustomerLogos(),
  366.             'badges' => $this->getAwardsBadges(),
  367.         ]);
  368.     }
  369.     #[Route(path'/product/recurring-billing'name'shortcut_recurring_billing'methods: ['GET'])]
  370.     public function shortcutRecurringBilling(): Response
  371.     {
  372.         return new RedirectResponse('/product/subscription-billing'301);
  373.     }
  374.     #[Route(path'/payments'name'payments'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => 1'sitemap_changefreq' => 'weekly'])]
  375.     public function payments(): Response
  376.     {
  377.         return $this->render('payments.twig', [
  378.             'logos' => $this->getCustomerLogos(),
  379.             'badges' => $this->getAwardsBadges(),
  380.         ]);
  381.     }
  382.     #[Route(path'/pricing'name'pricing'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.25''sitemap_changefreq' => 'weekly'])]
  383.     public function pricing(): Response
  384.     {
  385.         return $this->render('pricing.twig');
  386.     }
  387.     #[Route(path'/partner'name'shortcut_partner'methods: ['GET'])]
  388.     public function shortcutPartner(): Response
  389.     {
  390.         return new RedirectResponse('/about/partners'301);
  391.     }
  392.     #[Route(path'/about/partners'name'partner'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.5''sitemap_changefreq' => 'monthly'])]
  393.     public function partner(): Response
  394.     {
  395.         return $this->render('partner.twig');
  396.     }
  397.     #[Route(path'/about'name'about'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.5''sitemap_changefreq' => 'monthly'])]
  398.     public function about(): Response
  399.     {
  400.         return $this->render('about.twig', [
  401.             'logos' => $this->getCustomerLogos(),
  402.             'badges' => $this->getAwardsBadges(),
  403.         ]);
  404.     }
  405.     #[Route(path'/resources'name'resources'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.5''sitemap_changefreq' => 'monthly'])]
  406.     public function resources(): Response
  407.     {
  408.         return $this->render('resources/resources.twig');
  409.     }
  410.     #[Route(path'/customers'name'shortcut_customers'methods: ['GET'])]
  411.     public function shortcutCustomers(): Response
  412.     {
  413.         return new RedirectResponse('/resources/customers'301);
  414.     }
  415.     #[Route(path'/resources/customers'name'customers'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'weekly'])]
  416.     public function customers(Content $content): Response
  417.     {
  418.         return $this->render('resources/customers.twig', [
  419.             'caseStudies' => $content->getCaseStudies(),
  420.             'logos' => $this->getCustomerLogos(),
  421.         ]);
  422.     }
  423.     #[Route(path'/customers/{id}'name'shortcut_case_study'methods: ['GET'])]
  424.     public function shortcutCaseStudy(string $id): Response
  425.     {
  426.         return new RedirectResponse('/resources/customers/'.$id301);
  427.     }
  428.     #[Route(path'/resources/customers/{id}'name'case_study'methods: ['GET'])]
  429.     public function caseStudy(string $idContent $content): Response
  430.     {
  431.         // look up
  432.         $caseStudy $content->getCaseStudy($id);
  433.         if (!$caseStudy) {
  434.             throw new NotFoundHttpException();
  435.         }
  436.         return $this->render('case-studies/'.$id.'.twig', [
  437.             'caseStudy' => $caseStudy,
  438.             'caseStudyId' => $id,
  439.         ]);
  440.     }
  441.     #[Route(path'/resources/data-sheets'name'data_sheets'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'monthly'])]
  442.     public function dataSheets(): Response
  443.     {
  444.         return $this->render('resources/data-sheets.twig');
  445.     }
  446.     #[Route(path'/resources/tools'name'tools'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'monthly'])]
  447.     public function tools(): Response
  448.     {
  449.         return $this->render('resources/tools.twig');
  450.     }
  451.     #[Route(path'/resources/webinars'name'webinars'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'weekly'])]
  452.     public function webinars(Content $content): Response
  453.     {
  454.         return $this->render('resources/webinars.twig', [
  455.             'webinars' => $content->getWebinars(),
  456.         ]);
  457.     }
  458.     #[Route(path'/resources/videos/{id}'name'video'methods: ['GET'])]
  459.     public function video(string $idContent $content): Response
  460.     {
  461.         $video $content->getVideo($id);
  462.         if (!$video) {
  463.             throw new NotFoundHttpException();
  464.         }
  465.         if (isset($video['link'])) {
  466.             return new RedirectResponse($video['link']);
  467.         }
  468.         return $this->render('resources/video.twig', [
  469.             'video' => $video,
  470.         ]);
  471.     }
  472.     #[Route(path'/resources/videos'name'videos'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'weekly'])]
  473.     public function videos(Content $content): Response
  474.     {
  475.         return $this->render('resources/videos.twig', [
  476.             'videos' => $content->getVideos(),
  477.         ]);
  478.     }
  479.     #[Route(path'/resources/webinars/{id}'name'webinar'methods: ['GET'])]
  480.     public function webinar(string $idContent $content): Response
  481.     {
  482.         $webinar $content->getWebinar($id);
  483.         if (!$webinar) {
  484.             throw new NotFoundHttpException();
  485.         }
  486.         return $this->render('resources/webinar.twig', [
  487.             'webinar' => $webinar,
  488.         ]);
  489.     }
  490.     #[Route(path'/resources/white-papers'name'whitepapers'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'weekly'])]
  491.     public function whitepapers(Content $content): Response
  492.     {
  493.         return $this->render('resources/white-papers.twig', [
  494.             'whitepapers' => $content->getWhitePapers(),
  495.         ]);
  496.     }
  497.     #[Route(path'/resources/white-papers/thanks'name'white_paper_thanks'methods: ['GET'])]
  498.     public function whitePaperThanks(): Response
  499.     {
  500.         return $this->render('resources/white-paper-thanks.twig');
  501.     }
  502.     #[Route(path'/resources/white-papers/{id}'name'white_paper'methods: ['GET'])]
  503.     public function whitePaper(string $idContent $content): Response
  504.     {
  505.         $whitePaper $content->getWhitePaper($id);
  506.         if (!$whitePaper) {
  507.             throw new NotFoundHttpException();
  508.         }
  509.         if (isset($whitePaper['link'])) {
  510.             return new RedirectResponse($whitePaper['link']);
  511.         }
  512.         return $this->render('resources/white-paper.twig', [
  513.             'whitePaper' => $whitePaper,
  514.         ]);
  515.     }
  516.     #[Route(path'/careers'name'shortcut_careers'methods: ['GET'])]
  517.     public function shortcutCareers(): Response
  518.     {
  519.         return new RedirectResponse('/about/careers'301);
  520.     }
  521.     #[Route(path'/about/careers'name'careers'methods: ['GET'])]
  522.     public function careers(): Response
  523.     {
  524.         return new RedirectResponse('https://apply.workable.com/invoiced-1');
  525.     }
  526.     #[Route(path'/about/press'name'press'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'monthly'])]
  527.     public function press(): Response
  528.     {
  529.         return $this->render('press.twig');
  530.     }
  531.     #[Route(path'/solutions'name'solutions'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'monthly'])]
  532.     public function solutions(): Response
  533.     {
  534.         return $this->render('solutions.twig');
  535.     }
  536.     #[Route(path'/solutions/agencies'name'solution_agencies'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'monthly'])]
  537.     public function solutionAgencies(): Response
  538.     {
  539.         return $this->render('solutions/agencies.twig', [
  540.             'logos' => $this->getCustomerLogosTech(),
  541.             'badges' => $this->getAwardsBadges(),
  542.         ]);
  543.     }
  544.     private function getCustomerLogosTech(): array
  545.     {
  546.         $logos self::$customerLogosTech;
  547.         $logos array_slice($logos011);
  548.         foreach ($logos as &$logo) {
  549.             $logo['img'] = '/img/landing2/customer-logos/'.$logo['img'];
  550.         }
  551.         return $logos;
  552.     }
  553.     #[Route(path'/solutions/b2c'name'solution_b2c'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'monthly'])]
  554.     public function solutionB2c(): Response
  555.     {
  556.         return $this->render('solutions/b2c.twig');
  557.     }
  558.     #[Route(path'/solutions/healthcare'name'solution_healthcare'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'monthly'])]
  559.     public function solutionHealthcare(): Response
  560.     {
  561.         return $this->render('solutions/healthcare.twig', [
  562.             'logos' => $this->getCustomerLogosHealthcare(),
  563.             'badges' => $this->getAwardsBadges(),
  564.         ]);
  565.     }
  566.     private function getCustomerLogosHealthcare(): array
  567.     {
  568.         $logos self::$customerLogosHealthcare;
  569.         $logos array_slice($logos08);
  570.         foreach ($logos as &$logo) {
  571.             $logo['img'] = '/img/landing2/customer-logos/'.$logo['img'];
  572.         }
  573.         return $logos;
  574.     }
  575.     #[Route(path'/solutions/insurance'name'solution_insurance'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'monthly'])]
  576.     public function solutionInsurance(): Response
  577.     {
  578.         return $this->render('solutions/insurance.twig', [
  579.             'logos' => $this->getCustomerLogosInsurance(),
  580.             'badges' => $this->getAwardsBadges(),
  581.         ]);
  582.     }
  583.     private function getCustomerLogosInsurance(): array
  584.     {
  585.         $logos self::$customerLogosInsurance;
  586.         $logos array_slice($logos04);
  587.         foreach ($logos as &$logo) {
  588.             $logo['img'] = '/img/landing2/customer-logos/'.$logo['img'];
  589.         }
  590.         return $logos;
  591.     }
  592.     #[Route(path'/solutions/legal'name'solution_legal'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'monthly'])]
  593.     public function solutionLegal(): Response
  594.     {
  595.         return $this->render('solutions/legal.twig', [
  596.             'logos' => $this->getCustomerLogos(),
  597.             'badges' => $this->getAwardsBadges(),
  598.         ]);
  599.     }
  600.     #[Route(path'/solutions/technology'name'solution_technology'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'monthly'])]
  601.     public function solutionTechnology(): Response
  602.     {
  603.         return $this->render('solutions/technology.twig', ['logos' => $this->getCustomerLogosTech()]);
  604.     }
  605.     #[Route(path'/solutions/utilities'name'solution_utilities'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.7''sitemap_changefreq' => 'monthly'])]
  606.     public function solutionUtilities(): Response
  607.     {
  608.         return $this->render('solutions/utilities.twig', [
  609.             'logos' => $this->getCustomerLogos(),
  610.             'badges' => $this->getAwardsBadges(),
  611.         ]);
  612.     }
  613.     #[Route(path'/terms'name'terms'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.25''sitemap_changefreq' => 'monthly'])]
  614.     public function terms(): Response
  615.     {
  616.         return $this->render('terms.twig');
  617.     }
  618.     #[Route(path'/terms/enterprise'name'enterprise_terms'methods: ['GET'])]
  619.     public function enterpriseTerms(): Response
  620.     {
  621.         return $this->render('terms-enterprise.twig');
  622.     }
  623.     #[Route(path'/privacy'name'privacy'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.25''sitemap_changefreq' => 'monthly'])]
  624.     public function privacy(): Response
  625.     {
  626.         return $this->render('privacy.twig');
  627.     }
  628.     #[Route(path'/savings-calculator'name'savings_calculator'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.5''sitemap_changefreq' => 'monthly'])]
  629.     public function savingsCalculator(): Response
  630.     {
  631.         return $this->render('resources/savings-calculator.twig');
  632.     }
  633.     #[Route(path'/contact'name'contact'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.5''sitemap_changefreq' => 'monthly'])]
  634.     public function contact(): Response
  635.     {
  636.         return $this->render('/contact.twig');
  637.     }
  638.     #[Route(path'/faq'name'shortcut_faq'methods: ['GET'])]
  639.     public function shortcutFaq(): Response
  640.     {
  641.         return new RedirectResponse('https://docs.invoiced.com/faqs');
  642.     }
  643.     #[Route(path'/resellerprogram'name'shortcut_reseller_program'methods: ['GET'])]
  644.     public function shortcutResellerProgram(): Response
  645.     {
  646.         return new RedirectResponse('https://info.invoiced.com/reseller');
  647.     }
  648.     #[Route(path'/support'name'shortcut_support'methods: ['GET'])]
  649.     public function shortcutSupport(): Response
  650.     {
  651.         return new RedirectResponse('/resources/support'301);
  652.     }
  653.     #[Route(path'/resources/support'name'support'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.5''sitemap_changefreq' => 'monthly'])]
  654.     public function support(): Response
  655.     {
  656.         return $this->render('resources/support.twig');
  657.     }
  658.     #[Route(path'/intro-video'name'intro_video'methods: ['GET'])]
  659.     public function introVideo(): Response
  660.     {
  661.         return new RedirectResponse('/resources/videos/intro-video'301);
  662.     }
  663.     #[Route(path'/billing'name'billing'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.5''sitemap_changefreq' => 'monthly'])]
  664.     public function billing(): Response
  665.     {
  666.         return $this->render('product/billing.twig', [
  667.             'logos' => $this->getCustomerLogos(),
  668.             'badges' => $this->getAwardsBadges(),
  669.         ]);
  670.     }
  671.     #[Route(path'/collections'name'collections'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.5''sitemap_changefreq' => 'monthly'])]
  672.     public function collections(): Response
  673.     {
  674.         return $this->render('product/collections.twig', [
  675.             'logos' => $this->getCustomerLogos(),
  676.             'badges' => $this->getAwardsBadges(),
  677.         ]);
  678.     }
  679.     #[Route(path'/ar-intelligence'name'analytics'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.5''sitemap_changefreq' => 'monthly'])]
  680.     public function arIntelligence(): Response
  681.     {
  682.         return $this->render('product/analytics.twig', [
  683.             'logos' => $this->getCustomerLogos(),
  684.             'badges' => $this->getAwardsBadges(),
  685.         ]);
  686.     }
  687.     #[Route(path'/payment-acceptance'name'payment_acceptance'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.5''sitemap_changefreq' => 'monthly'])]
  688.     public function paymentAcceptance(): Response
  689.     {
  690.         return $this->render('product/payment-acceptance.twig', ['badges' => $this->getAwardsBadges()]);
  691.     }
  692.     #[Route(path'/amex'name'shortcut_amex'methods: ['GET'])]
  693.     public function shortcutAmex(): Response
  694.     {
  695.         return new RedirectResponse('https://info.invoiced.com/amex');
  696.     }
  697.     #[Route(path'/mastercard'name'shortcut_mastercard'methods: ['GET'])]
  698.     public function shortcutMastercard(): Response
  699.     {
  700.         return new RedirectResponse('https://info.invoiced.com/mastercard');
  701.     }
  702.     #[Route(path'/visa'name'shortcut_visa'methods: ['GET'])]
  703.     public function shortcutVisa(): Response
  704.     {
  705.         return new RedirectResponse('https://info.invoiced.com/visa');
  706.     }
  707.     #[Route(path'/gocardless'name'gocardless_landing'methods: ['GET'])]
  708.     public function gocardless(): Response
  709.     {
  710.         return new RedirectResponse('https://docs.invoiced.com/integrations/gocardless'301);
  711.     }
  712.     #[Route(path'/stripe'name'stripe_landing'methods: ['GET'])]
  713.     public function stripe(): Response
  714.     {
  715.         return new RedirectResponse('https://docs.invoiced.com/integrations/stripe'301);
  716.     }
  717.     #[Route(path'/intacct'name'legacy_intacct_shortcut'methods: ['GET'])]
  718.     #[Route(path'/product/integrations/intacct'name'legacy_intacct'methods: ['GET'])]
  719.     #[Route(path'/sageintacct'name'intacct_shortcut'methods: ['GET'])]
  720.     public function shortcutIntacct(): Response
  721.     {
  722.         return new RedirectResponse('/product/integrations/sageintacct'301);
  723.     }
  724.     #[Route(path'/product/integrations/sageintacct'name'intacct_landing'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.5''sitemap_changefreq' => 'monthly'])]
  725.     public function intacct(Request $request): Response
  726.     {
  727.         $request->query->add([
  728.             'utm_source' => 'Intacct',
  729.             'utm_medium' => 'landing',
  730.             'utm_content' => 'visit',
  731.             'utm_campaign' => 'partner',
  732.         ]);
  733.         return $this->render('partners/intacct.twig');
  734.     }
  735.     #[Route(path'/product/integrations/netsuite'name'netsuite_landing'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.5''sitemap_changefreq' => 'monthly'])]
  736.     public function netsuite(Request $request): Response
  737.     {
  738.         $request->query->add([
  739.             'utm_source' => 'NetSuite',
  740.             'utm_medium' => 'landing',
  741.             'utm_content' => 'visit',
  742.             'utm_campaign' => 'partner',
  743.         ]);
  744.         return $this->render('partners/netsuite.twig');
  745.     }
  746.     #[Route(path'/quickbooks'name'shortcut_quickbooks'methods: ['GET'])]
  747.     public function shortcutQuickBooks(): Response
  748.     {
  749.         return new RedirectResponse('/product/integrations/quickbooks'301);
  750.     }
  751.     #[Route(path'/product/integrations/quickbooks'name'quickbooks_landing'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.5''sitemap_changefreq' => 'monthly'])]
  752.     public function quickbooks(Request $request): Response
  753.     {
  754.         $request->query->add([
  755.             'utm_source' => 'QuickBooks',
  756.             'utm_medium' => 'landing',
  757.             'utm_content' => 'visit',
  758.             'utm_campaign' => 'partner',
  759.         ]);
  760.         return $this->render('partners/quickbooks.twig', [
  761.             'disconnected' => $request->query->get('disconnected'),
  762.         ]);
  763.     }
  764.     #[Route(path'/xero'name'shortcut_xero'methods: ['GET'])]
  765.     public function shortcutXero(): Response
  766.     {
  767.         return new RedirectResponse('/product/integrations/xero'301);
  768.     }
  769.     #[Route(path'/product/integrations/xero'name'xero_landing'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.5''sitemap_changefreq' => 'monthly'])]
  770.     public function xero(Request $request): Response
  771.     {
  772.         $request->query->add([
  773.             'utm_source' => 'Xero',
  774.             'utm_medium' => 'landing',
  775.             'utm_content' => 'visit',
  776.             'utm_campaign' => 'partner',
  777.         ]);
  778.         return $this->render('partners/xero.twig');
  779.     }
  780.     #[Route(path'/sitemap.xml'name'sitemap_xml'methods: ['GET'])]
  781.     public function sitemapXml(RouterInterface $routerRequest $requestCacheInterface $cacheBlog $blogContent $content): Response
  782.     {
  783.         if ($request->query->get('bust_cache')) {
  784.             $cache->delete('sitemap_xml');
  785.         }
  786.         $pages $cache->get('sitemap_xml', function (ItemInterface $item) use ($router$request$blog$content) {
  787.             $item->expiresAfter(86400); // rebuild sitemap.xml once per day
  788.             return $this->buildSitemapPages($router$request$blog$content);
  789.         });
  790.         // build the sitemap.xml file using Twig
  791.         $response = new Response(''200, ['Content-Type' => 'text/xml']);
  792.         return $this->render('sitemap.xml.twig', [
  793.             'pages' => $pages,
  794.         ], $response);
  795.     }
  796.     private function buildSitemapPages(RouterInterface $routerRequest $requestBlog $blogContent $content): array
  797.     {
  798.         $pages = [];
  799.         // add the static routes
  800.         foreach ($router->getRouteCollection()->all() as $route) {
  801.             if (!$route->getOption('in_sitemap')) {
  802.                 continue;
  803.             }
  804.             $pages[] = [
  805.                 'url' => $request->getUriForPath($route->getPath()),
  806.                 'changefreq' => $route->getOption('sitemap_changefreq') ?? 'monthly',
  807.                 'priority' => $route->getOption('sitemap_priority') ?? 0.7,
  808.             ];
  809.         }
  810.         // add blog routes
  811.         foreach ($blog->getPosts(-1) as $post) {
  812.             $pages[] = [
  813.                 'url' => $this->generateUrl('blog_post', ['id' => $post['slug']], UrlGeneratorInterface::ABSOLUTE_URL),
  814.                 'lastmod' => date('Y-m-d'strtotime($post['updated'])),
  815.             ];
  816.         }
  817.         foreach ($blog->getAuthors() as $author) {
  818.             $pages[] = [
  819.                 'url' => $this->generateUrl('blog_author', ['author' => $author['slug']], UrlGeneratorInterface::ABSOLUTE_URL),
  820.                 'changefreq' => 'daily',
  821.                 'priority' => 0.4,
  822.             ];
  823.         }
  824.         foreach ($blog->getTags() as $tag) {
  825.             $pages[] = [
  826.                 'url' => $this->generateUrl('blog_category', ['tag' => $tag['slug']], UrlGeneratorInterface::ABSOLUTE_URL),
  827.                 'changefreq' => 'daily',
  828.                 'priority' => 0.4,
  829.             ];
  830.         }
  831.         // add case study routes
  832.         foreach ($content->getCaseStudies() as $caseStudy) {
  833.             $pages[] = [
  834.                 'url' => $this->generateUrl('case_study', ['id' => $caseStudy['slug']], UrlGeneratorInterface::ABSOLUTE_URL),
  835.                 'changefreq' => 'monthly',
  836.                 'priority' => 0.6,
  837.             ];
  838.         }
  839.         // add video routes
  840.         foreach ($content->getVideos() as $video) {
  841.             $pages[] = [
  842.                 'url' => $video['link'] ?? $this->generateUrl('video', ['id' => $video['slug']], UrlGeneratorInterface::ABSOLUTE_URL),
  843.                 'changefreq' => 'weekly',
  844.                 'priority' => 0.6,
  845.             ];
  846.         }
  847.         // add webinar routes
  848.         foreach ($content->getWebinars() as $webinar) {
  849.             $pages[] = [
  850.                 'url' => $this->generateUrl('webinar', ['id' => $webinar['slug']], UrlGeneratorInterface::ABSOLUTE_URL),
  851.                 'changefreq' => 'weekly',
  852.                 'priority' => 0.6,
  853.             ];
  854.         }
  855.         // add white paper routes
  856.         foreach ($content->getWhitePapers() as $whitePaper) {
  857.             $pages[] = [
  858.                 'url' => $whitePaper['link'] ?? $this->generateUrl('white_paper', ['id' => $whitePaper['slug']], UrlGeneratorInterface::ABSOLUTE_URL),
  859.                 'changefreq' => 'weekly',
  860.                 'priority' => 0.6,
  861.             ];
  862.         }
  863.         // add the documentation routes
  864.         $pages[] = [
  865.             'url' => $request->getUriForPath('/resources/docs/api'),
  866.             'changefreq' => 'weekly',
  867.             'priority' => 0.7,
  868.         ];
  869.         return $pages;
  870.     }
  871.     #[Route(path'/schedule-demo'name'schedule_demo'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.8''sitemap_changefreq' => 'monthly'])]
  872.     public function scheduleDemo(Request $request): Response
  873.     {
  874.         $prefill = [];
  875.         if ($params $request->cookies->get('utm_params')) {
  876.             $prefill json_decode($paramstrue);
  877.             if (!is_array($prefill)) {
  878.                 $prefill = [];
  879.             }
  880.         }
  881.         // Do not cache demo booking pages
  882.         $response = new Response();
  883.         $response->headers->set('Cache-Control''no-cache, no-store, must-revalidate');
  884.         $response->headers->set('Pragma''no-cache');
  885.         $response->headers->set('Expires''0');
  886.         return $this->render('demo-1.twig', [
  887.             'prefillParams' => $prefill,
  888.         ], $response);
  889.     }
  890.     #[Route(path'/demo/2'name'schedule_demo_2'methods: ['GET'])]
  891.     public function scheduleDemo2(Request $request): Response
  892.     {
  893.         // Do not cache demo booking pages
  894.         $response = new Response();
  895.         $response->headers->set('Cache-Control''no-cache, no-store, must-revalidate');
  896.         $response->headers->set('Pragma''no-cache');
  897.         $response->headers->set('Expires''0');
  898.         if ($request->cookies->has('booked_demo')) {
  899.             $response->setContent('Thank you for scheduling a demo!');
  900.             return $response;
  901.         }
  902.         // validate the email domain has an MX record
  903.         $emailParts explode('@', (string) $request->query->get('email'));
  904.         $emailDomain '';
  905.         if (== count($emailParts)) {
  906.             [, $emailDomain] = $emailParts;
  907.         }
  908.         if (!$emailDomain || !checkdnsrr($emailDomain.'.''MX')) {
  909.             $response->setContent('Could not validate email address');
  910.             return $response;
  911.         }
  912.         return $this->render('demo-2.twig', [], $response);
  913.     }
  914.     #[Route(path'/demo/thanks'name'schedule_demo_thanks'methods: ['GET'])]
  915.     public function demoThanks(): Response
  916.     {
  917.         // Do not cache demo booking pages
  918.         $response = new Response();
  919.         $response->headers->set('Cache-Control''no-cache, no-store, must-revalidate');
  920.         $response->headers->set('Pragma''no-cache');
  921.         $response->headers->set('Expires''0');
  922.         // Visitors can only book one demo per month
  923.         $response->headers->setCookie(
  924.             new Cookie(
  925.                 'booked_demo',
  926.                 '1',
  927.                 strtotime('+30 days'),
  928.             )
  929.         );
  930.         return $this->render('demo-thanks.twig', [], $response);
  931.     }
  932.     #[Route(path'/download'name'download'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => '0.5''sitemap_changefreq' => 'monthly'])]
  933.     public function download(): Response
  934.     {
  935.         return $this->render('download.twig');
  936.     }
  937.     #[Route(path'/guides/ultimate-guide-automating-accounts-receivable-process'name'ultimate_guide_automating_accounts_receivable_process'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => 1'sitemap_changefreq' => 'weekly'])]
  938.     public function ultimateGuideAutomatingAccountsReceivableProcess(): Response
  939.     {
  940.         return $this->render('landing-page-ar-automation.twig', ['badges' => $this->getAwardsBadges()]);
  941.     }
  942.     #[Route(path'/guides/guide-automating-accounts-receivable-law-firms'name'guide_automating_accounts_receivable_law_firms'methods: ['GET'], options: ['in_sitemap' => true'sitemap_priority' => 1'sitemap_changefreq' => 'weekly'])]
  943.     public function guideAutomatingAccountsReceivableLawFirms(): Response
  944.     {
  945.         return $this->render('landing-page-ar-automation-law.twig', ['badges' => $this->getAwardsBadges()]);
  946.     }
  947. }