vendor/codefog/contao-news_categories/src/FrontendModule/NewsModule.php line 116

Open in your IDE?
  1. <?php
  2. namespace Codefog\NewsCategoriesBundle\FrontendModule;
  3. use Codefog\NewsCategoriesBundle\Criteria\NewsCriteria;
  4. use Codefog\NewsCategoriesBundle\Exception\NoNewsException;
  5. use Codefog\NewsCategoriesBundle\Model\NewsCategoryModel;
  6. use Codefog\NewsCategoriesBundle\NewsCategoriesManager;
  7. use Contao\BackendTemplate;
  8. use Contao\Controller;
  9. use Contao\Database;
  10. use Contao\Model\Collection;
  11. use Contao\ModuleNews;
  12. use Contao\NewsModel;
  13. use Contao\PageModel;
  14. use Contao\StringUtil;
  15. use Contao\System;
  16. use Haste\Input\Input;
  17. use Haste\Model\Model;
  18. abstract class NewsModule extends ModuleNews
  19. {
  20.     /**
  21.      * Active category.
  22.      *
  23.      * @var NewsCategoryModel
  24.      */
  25.     protected $activeCategory null;
  26.     /**
  27.      * Active categories.
  28.      *
  29.      * @var Collection|null
  30.      */
  31.     protected $activeCategories;
  32.     /**
  33.      * News categories of the current news item.
  34.      *
  35.      * @var array
  36.      */
  37.     protected $currentNewsCategories = [];
  38.     /**
  39.      * @var NewsCategoriesManager
  40.      */
  41.     protected $manager;
  42.     /**
  43.      * @var PageModel|null
  44.      */
  45.     protected $targetPage;
  46.     /**
  47.      * Display a wildcard in the back end.
  48.      *
  49.      * @return string
  50.      */
  51.     public function generate()
  52.     {
  53.         if (TL_MODE === 'BE') {
  54.             $template = new BackendTemplate('be_wildcard');
  55.             $template->wildcard '### '.mb_strtoupper($GLOBALS['TL_LANG']['FMD'][$this->type][0]).' ###';
  56.             $template->title $this->headline;
  57.             $template->id $this->id;
  58.             $template->link $this->name;
  59.             $template->href 'contao/main.php?do=themes&amp;table=tl_module&amp;act=edit&amp;id='.$this->id;
  60.             return $template->parse();
  61.         }
  62.         $this->news_archives $this->sortOutProtected(StringUtil::deserialize($this->news_archivestrue));
  63.         // Return if there are no archives
  64.         if (=== \count($this->news_archives)) {
  65.             return '';
  66.         }
  67.         $this->manager System::getContainer()->get('codefog_news_categories.manager');
  68.         $this->currentNewsCategories $this->getCurrentNewsCategories();
  69.         return parent::generate();
  70.     }
  71.     /**
  72.      * Get the URL category separator character.
  73.      *
  74.      * @return string
  75.      */
  76.     public static function getCategorySeparator()
  77.     {
  78.         return '__';
  79.     }
  80.     /**
  81.      * Get the categories.
  82.      *
  83.      * @return Collection|null
  84.      */
  85.     protected function getCategories()
  86.     {
  87.         $customCategories $this->news_customCategories StringUtil::deserialize($this->news_categoriestrue) : [];
  88.         // Get the subcategories of custom categories
  89.         if (\count($customCategories) > 0) {
  90.             $customCategories NewsCategoryModel::getAllSubcategoriesIds($customCategories);
  91.         }
  92.         // Get all categories whether they have news or not
  93.         if ($this->news_showEmptyCategories) {
  94.             if (\count($customCategories) > 0) {
  95.                 $categories NewsCategoryModel::findPublishedByIds($customCategories);
  96.             } else {
  97.                 $categories NewsCategoryModel::findPublished();
  98.             }
  99.         } else {
  100.             // Get the categories that do have news assigned
  101.             $categories NewsCategoryModel::findPublishedByArchives($this->news_archives$customCategories);
  102.         }
  103.         return $categories;
  104.     }
  105.     /**
  106.      * Get the active categories.
  107.      *
  108.      * @param array $customCategories
  109.      *
  110.      * @return Collection|null
  111.      */
  112.     protected function getActiveCategories(array $customCategories = [])
  113.     {
  114.         $param System::getContainer()->get('codefog_news_categories.manager')->getParameterName();
  115.         if (!($aliases Input::get($param))) {
  116.             return null;
  117.         }
  118.         $aliases StringUtil::trimsplit(static::getCategorySeparator(), $aliases);
  119.         $aliases = \array_unique(\array_filter($aliases));
  120.         if (=== \count($aliases)) {
  121.             return null;
  122.         }
  123.         // Get the categories that do have news assigned
  124.         $models NewsCategoryModel::findPublishedByArchives($this->news_archives$customCategories$aliases);
  125.         // No models have been found but there are some aliases present
  126.         if (null === $models && !== \count($aliases)) {
  127.             Controller::redirect($this->getTargetPage()->getFrontendUrl());
  128.         }
  129.         // Validate the provided aliases with the categories found
  130.         if (null !== $models) {
  131.             $realAliases = [];
  132.             /** @var NewsCategoryModel $model */
  133.             foreach ($models as $model) {
  134.                 $realAliases[] = $this->manager->getCategoryAlias($model$GLOBALS['objPage']);
  135.             }
  136.             if (\count(\array_diff($aliases$realAliases)) > 0) {
  137.                 Controller::redirect($this->getTargetPage()->getFrontendUrl(\sprintf(
  138.                     '/%s/%s',
  139.                     $this->manager->getParameterName($GLOBALS['objPage']->rootId),
  140.                     \implode(static::getCategorySeparator(), $realAliases)
  141.                 )));
  142.             }
  143.         }
  144.         return $models;
  145.     }
  146.     /**
  147.      * Get the inactive categories.
  148.      *
  149.      * @param array $customCategories
  150.      *
  151.      * @return Collection|null
  152.      */
  153.     protected function getInactiveCategories(array $customCategories = [])
  154.     {
  155.         $excludedIds = [];
  156.         // Find only the categories that still can display some results combined with active categories
  157.         if (null !== $this->activeCategories) {
  158.             // Union filtering
  159.             if ($this->news_filterCategoriesUnion) {
  160.                 $excludedIds $this->activeCategories->fetchEach('id');
  161.             } else {
  162.                 // Intersection filtering
  163.                 $columns = [];
  164.                 $values = [];
  165.                 // Collect the news that match all active categories
  166.                 /** @var NewsCategoryModel $activeCategory */
  167.                 foreach ($this->activeCategories as $activeCategory) {
  168.                     $criteria = new NewsCriteria(System::getContainer()->get('contao.framework'));
  169.                     try {
  170.                         $criteria->setBasicCriteria($this->news_archives);
  171.                         $criteria->setCategory($activeCategory->idfalse, (bool) $this->news_includeSubcategories);
  172.                     } catch (NoNewsException $e) {
  173.                         continue;
  174.                     }
  175.                     $columns = \array_merge($columns$criteria->getColumns());
  176.                     $values = \array_merge($values$criteria->getValues());
  177.                 }
  178.                 // Should not happen but you never know
  179.                 if (=== \count($columns)) {
  180.                     return null;
  181.                 }
  182.                 $newsIds Database::getInstance()
  183.                     ->prepare('SELECT id FROM tl_news WHERE '.\implode(' AND '$columns))
  184.                     ->execute($values)
  185.                     ->fetchEach('id')
  186.                 ;
  187.                 if (=== \count($newsIds)) {
  188.                     return null;
  189.                 }
  190.                 $categoryIds Model::getRelatedValues('tl_news''categories'$newsIds);
  191.                 $categoryIds = \array_map('intval'$categoryIds);
  192.                 $categoryIds = \array_unique(\array_filter($categoryIds));
  193.                 // Include the parent categories
  194.                 if ($this->news_includeSubcategories) {
  195.                     foreach ($categoryIds as $categoryId) {
  196.                         $categoryIds = \array_merge($categoryIds, \array_map('intval'Database::getInstance()->getParentRecords($categoryId'tl_news_category')));
  197.                     }
  198.                 }
  199.                 // Remove the active categories, so they are not considered again
  200.                 $categoryIds = \array_diff($categoryIds$this->activeCategories->fetchEach('id'));
  201.                 // Filter by custom categories
  202.                 if (\count($customCategories) > 0) {
  203.                     $categoryIds = \array_intersect($categoryIds$customCategories);
  204.                 }
  205.                 $categoryIds = \array_values(\array_unique($categoryIds));
  206.                 if (=== \count($categoryIds)) {
  207.                     return null;
  208.                 }
  209.                 $customCategories $categoryIds;
  210.             }
  211.         }
  212.         return NewsCategoryModel::findPublishedByArchives($this->news_archives$customCategories, [], $excludedIds);
  213.     }
  214.     /**
  215.      * Get the target page.
  216.      *
  217.      * @return PageModel
  218.      */
  219.     protected function getTargetPage()
  220.     {
  221.         if (null === $this->targetPage) {
  222.             if ($this->jumpTo 0
  223.                 && (int) $GLOBALS['objPage']->id !== (int) $this->jumpTo
  224.                 && null !== ($target PageModel::findPublishedById($this->jumpTo))
  225.             ) {
  226.                 $this->targetPage $target;
  227.             } else {
  228.                 $this->targetPage $GLOBALS['objPage'];
  229.             }
  230.         }
  231.         return $this->targetPage;
  232.     }
  233.     /**
  234.      * Get the category IDs of the current news item.
  235.      *
  236.      * @return array
  237.      */
  238.     protected function getCurrentNewsCategories()
  239.     {
  240.         if (!($alias Input::getAutoItem('items'falsetrue))
  241.             || null === ($news NewsModel::findPublishedByParentAndIdOrAlias($alias$this->news_archives))
  242.         ) {
  243.             return [];
  244.         }
  245.         $ids Model::getRelatedValues('tl_news''categories'$news->id);
  246.         $ids = \array_map('intval', \array_unique($ids));
  247.         return $ids;
  248.     }
  249.     /**
  250.      * Generate the item.
  251.      *
  252.      * @param string                 $url
  253.      * @param string                 $link
  254.      * @param string                 $title
  255.      * @param string                 $cssClass
  256.      * @param bool                   $isActive
  257.      * @param string                 $subitems
  258.      * @param NewsCategoryModel|null $category
  259.      *
  260.      * @return array
  261.      */
  262.     protected function generateItem($url$link$title$cssClass$isActive$subitems ''NewsCategoryModel $category null)
  263.     {
  264.         $data = [];
  265.         // Set the data from category
  266.         if (null !== $category) {
  267.             $data $category->row();
  268.         }
  269.         $data['isActive'] = $isActive;
  270.         $data['subitems'] = $subitems;
  271.         $data['class'] = $cssClass;
  272.         $data['title'] = StringUtil::specialchars($title);
  273.         $data['linkTitle'] = StringUtil::specialchars($title);
  274.         $data['link'] = $link;
  275.         $data['href'] = ampersand($url);
  276.         $data['quantity'] = 0;
  277.         // Add the "active" class
  278.         if ($isActive) {
  279.             $data['class'] = \trim($data['class'].' active');
  280.         }
  281.         // Add the "submenu" class
  282.         if ($subitems) {
  283.             $data['class'] = \trim($data['class'].' submenu');
  284.         }
  285.         // Add the news quantity
  286.         if ($this->news_showQuantity) {
  287.             if (null === $category) {
  288.                 $data['quantity'] = NewsCategoryModel::getUsage($this->news_archivesnullfalse, [], (bool) $this->news_filterCategoriesUnion);
  289.             } else {
  290.                 $data['quantity'] = NewsCategoryModel::getUsage(
  291.                     $this->news_archives,
  292.                     $category->id,
  293.                     (bool) $this->news_includeSubcategories,
  294.                     (null !== $this->activeCategories) ? $this->activeCategories->fetchEach('id') : [],
  295.                     (bool) $this->news_filterCategoriesUnion
  296.                 );
  297.             }
  298.         }
  299.         // Add the image
  300.         if (null !== $category && null !== ($image $this->manager->getImage($category))) {
  301.             $data['image'] = new \stdClass();
  302.             Controller::addImageToTemplate($data['image'], [
  303.                 'singleSRC' => $image->path,
  304.                 'size' => $this->news_categoryImgSize,
  305.                 'alt' => $title,
  306.                 'imageTitle' => $title,
  307.             ]);
  308.         } else {
  309.             $data['image'] = null;
  310.         }
  311.         return $data;
  312.     }
  313.     /**
  314.      * Generate the item CSS class.
  315.      *
  316.      * @param NewsCategoryModel $category
  317.      *
  318.      * @return string
  319.      */
  320.     protected function generateItemCssClass(NewsCategoryModel $category)
  321.     {
  322.         $cssClasses = [$category->getCssClass()];
  323.         // Add the trail class
  324.         if (\in_array((int) $category->id$this->manager->getTrailIds($category), true)) {
  325.             $cssClasses[] = 'trail';
  326.         } elseif (null !== $this->activeCategory && \in_array((int) $category->id$this->manager->getTrailIds($this->activeCategory), true)) {
  327.             $cssClasses[] = 'trail';
  328.         }
  329.         // Add the news trail class
  330.         if (\in_array((int) $category->id$this->currentNewsCategoriestrue)) {
  331.             $cssClasses[] = 'news_trail';
  332.         }
  333.         return \implode(' '$cssClasses);
  334.     }
  335. }