vendor/terminal42/contao-changelanguage/src/FrontendModule/ChangeLanguageModule.php line 126

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace Terminal42\ChangeLanguage\FrontendModule;
  4. use Contao\BackendTemplate;
  5. use Contao\FrontendTemplate;
  6. use Contao\Input;
  7. use Contao\Module;
  8. use Contao\PageModel;
  9. use Contao\StringUtil;
  10. use Contao\System;
  11. use Symfony\Component\Routing\Exception\ExceptionInterface;
  12. use Terminal42\ChangeLanguage\Event\ChangelanguageNavigationEvent;
  13. use Terminal42\ChangeLanguage\Helper\AlternateLinks;
  14. use Terminal42\ChangeLanguage\Helper\LanguageText;
  15. use Terminal42\ChangeLanguage\Navigation\NavigationFactory;
  16. use Terminal42\ChangeLanguage\Navigation\NavigationItem;
  17. use Terminal42\ChangeLanguage\Navigation\UrlParameterBag;
  18. use Terminal42\ChangeLanguage\PageFinder;
  19. /**
  20.  * @property bool  $hideActiveLanguage
  21.  * @property bool  $hideNoFallback
  22.  * @property bool  $customLanguage
  23.  * @property array $customLanguageText
  24.  */
  25. class ChangeLanguageModule extends Module
  26. {
  27.     /**
  28.      * @var string
  29.      */
  30.     protected $strTemplate 'mod_changelanguage';
  31.     private static ?AlternateLinks $alternateLinks null;
  32.     public function getAlternateLinks(): AlternateLinks
  33.     {
  34.         if (null === self::$alternateLinks) {
  35.             self::$alternateLinks = new AlternateLinks();
  36.         }
  37.         return self::$alternateLinks;
  38.     }
  39.     public function generate(): string
  40.     {
  41.         $request System::getContainer()->get('request_stack')->getCurrentRequest();
  42.         $scopeMatcher System::getContainer()->get('contao.routing.scope_matcher');
  43.         if (null !== $request && $scopeMatcher->isBackendRequest($request)) {
  44.             $template = new BackendTemplate('be_wildcard');
  45.             $template->wildcard '### '.strtoupper($GLOBALS['TL_LANG']['FMD'][$this->type][0]).' ###';
  46.             $template->title $this->headline;
  47.             $template->id $this->id;
  48.             $template->link $this->name;
  49.             $template->href System::getContainer()->get('router')->generate(
  50.                 'contao_backend',
  51.                 ['do' => 'themes''table' => 'tl_module''act' => 'edit''id' => $this->id]
  52.             );
  53.             return $template->parse();
  54.         }
  55.         $buffer parent::generate();
  56.         return '' === (string) $this->Template->items '' $buffer;
  57.     }
  58.     protected function compile(): void
  59.     {
  60.         $currentPage $this->getCurrentPage();
  61.         $pageFinder = new PageFinder();
  62.         if ($this->customLanguage) {
  63.             $languageText LanguageText::createFromOptionWizard($this->customLanguageText);
  64.         } else {
  65.             $languageText = new LanguageText();
  66.         }
  67.         $navigationFactory = new NavigationFactory($pageFinder$languageText$currentPageSystem::getContainer()->get('contao.intl.locales')->getLocales());
  68.         $navigationItems $navigationFactory->findNavigationItems($currentPage);
  69.         // Do not generate module or header if there is none or only one link
  70.         if (\count($navigationItems) < 2) {
  71.             return;
  72.         }
  73.         $templateItems = [];
  74.         $headerLinks $this->getAlternateLinks();
  75.         $queryParameters $currentPage->languageQuery trimsplit(','$currentPage->languageQuery) : [];
  76.         $defaultUrlParameters $this->createUrlParameterBag($queryParameters);
  77.         foreach ($navigationItems as $item) {
  78.             $urlParameters = clone $defaultUrlParameters;
  79.             if (
  80.                 false === $this->executeHook($item$urlParameters)
  81.                 || ($this->hideNoFallback && !$item->isDirectFallback())
  82.             ) {
  83.                 continue;
  84.             }
  85.             if ($item->isDirectFallback() && !$headerLinks->has($item->getLanguageTag())) {
  86.                 try {
  87.                     $headerLinks->addFromNavigationItem($item$urlParameters);
  88.                     if ($item->getRootPage()->fallback && !$item->getRootPage()->languageRoot) {
  89.                         $headerLinks->setDefault($item->getHref($urlParameters), $item->getTitle());
  90.                     }
  91.                 } catch (ExceptionInterface $e) {
  92.                     // Ignore unroutable pages
  93.                 }
  94.             }
  95.             // Remove active language from navigation but not from header links!
  96.             if ($this->hideActiveLanguage && $item->isCurrentPage()) {
  97.                 continue;
  98.             }
  99.             $templateItems[] = $this->generateTemplateArray($item$urlParameters);
  100.         }
  101.         $this->Template->items $this->generateNavigationTemplate($templateItems);
  102.         $GLOBALS['TL_HEAD']['changelanguage_headers'] = $headerLinks->generate();
  103.     }
  104.     /**
  105.      * Generates array suitable for nav_default template.
  106.      */
  107.     protected function generateTemplateArray(NavigationItem $itemUrlParameterBag $urlParameterBag): array
  108.     {
  109.         return [
  110.             'isActive' => $item->isCurrentPage(),
  111.             'class' => 'lang-'.$item->getNormalizedLanguage().($item->isDirectFallback() ? '' ' nofallback').($item->isCurrentPage() ? ' active' ''),
  112.             'link' => $item->getLabel(),
  113.             'subitems' => '',
  114.             'href' => StringUtil::specialchars($item->getHref($urlParameterBagtrue)),
  115.             'title' => StringUtil::specialchars(strip_tags($item->getTitle())),
  116.             'pageTitle' => StringUtil::specialchars(strip_tags($item->getPageTitle())),
  117.             'accesskey' => '',
  118.             'tabindex' => '',
  119.             'nofollow' => false,
  120.             'rel' => ' hreflang="'.$item->getLanguageTag().'"'.(empty($item->getAriaLabel()) ? '' ' aria-label="'.$item->getAriaLabel().'"'),
  121.             'target' => ($item->isNewWindow() ? ' target="_blank"' ''),
  122.             'item' => $item,
  123.             'languageTag' => $item->getLanguageTag(),
  124.         ];
  125.     }
  126.     protected function generateNavigationTemplate(array $items): string
  127.     {
  128.         $objTemplate = new FrontendTemplate($this->navigationTpl ?: 'nav_default');
  129.         $objTemplate->setData($this->arrData);
  130.         $objTemplate->level 'level_1';
  131.         $objTemplate->items $items;
  132.         return $objTemplate->parse();
  133.     }
  134.     protected function getCurrentPage(): PageModel
  135.     {
  136.         global $objPage;
  137.         return $objPage;
  138.     }
  139.     /**
  140.      * Creates an UrlParameterBag from the current environment.
  141.      *
  142.      * @param array $queryParameters An array of query parameters to keep
  143.      */
  144.     protected function createUrlParameterBag(array $queryParameters = []): UrlParameterBag
  145.     {
  146.         $attributes = [];
  147.         $query = [];
  148.         $input $_GET;
  149.         // the current page language is set in $_GET
  150.         unset($input['language'], $input['auto_item']);
  151.         $currentQuery = [];
  152.         if (!empty($_SERVER['QUERY_STRING'])) {
  153.             parse_str($_SERVER['QUERY_STRING'], $currentQuery);
  154.         }
  155.         foreach ($input as $k => $value) {
  156.             // GET parameters can be an array
  157.             $value Input::get($kfalsetrue);
  158.             if (empty($value)) {
  159.                 continue;
  160.             }
  161.             if (!\array_key_exists($k$currentQuery)) {
  162.                 $attributes[$k] = (string) $value;
  163.             } elseif (\in_array($k$queryParametersfalse)) {
  164.                 $query[$k] = $value;
  165.             }
  166.         }
  167.         return new UrlParameterBag($attributes$query);
  168.     }
  169.     /**
  170.      * Returns false if navigation item should be skipped.
  171.      */
  172.     protected function executeHook(NavigationItem $navigationItemUrlParameterBag $urlParameterBag): bool
  173.     {
  174.         // HOOK: allow extensions to modify url parameters
  175.         if (
  176.             isset($GLOBALS['TL_HOOKS']['changelanguageNavigation'])
  177.             && \is_array($GLOBALS['TL_HOOKS']['changelanguageNavigation'])
  178.         ) {
  179.             $event = new ChangelanguageNavigationEvent($navigationItem$urlParameterBag);
  180.             foreach ($GLOBALS['TL_HOOKS']['changelanguageNavigation'] as $callback) {
  181.                 System::importStatic($callback[0])->{$callback[1]}($event);
  182.                 if ($event->isPropagationStopped()) {
  183.                     break;
  184.                 }
  185.             }
  186.             return !$event->isSkipped();
  187.         }
  188.         return true;
  189.     }
  190. }