vendor/alnv/catalog-manager/library/alnv/CatalogView.php line 649

Open in your IDE?
  1. <?php
  2. namespace CatalogManager;
  3. class CatalogView extends CatalogController
  4. {
  5.     public $strMode;
  6.     public $strMasterID;
  7.     public $strTemplate;
  8.     public $objMainTemplate;
  9.     public $arrOptions = [];
  10.     public $strTimeFormat 'H:i';
  11.     public $strDateFormat 'd.m.Y';
  12.     public $strDateTimeFormat 'd.m.Y H:i';
  13.     public $arrPage = [];
  14.     public $arrViewPage = [];
  15.     public $arrMasterPage = [];
  16.     public $arrFrontendEditingPage = [];
  17.     protected $arrGroups = [];
  18.     protected $arrCatalog = [];
  19.     protected $arrParseAsArray = [];
  20.     protected $arrEntityFields = [];
  21.     protected $arrCatalogFields = [];
  22.     protected $arrRelatedTables = [];
  23.     protected $blnMapViewMode false;
  24.     protected $blnShowAsGroup false;
  25.     protected $blnHasOperations false;
  26.     protected $arrRoutingParameter = [];
  27.     protected $blnGoogleMapScript false;
  28.     protected $arrCatalogStaticFields = [];
  29.     protected $arrCatalogMapViewOptions = [];
  30.     public function __construct()
  31.     {
  32.         parent::__construct();
  33.         $this->import('IconGetter');
  34.         $this->import('CatalogInput');
  35.         $this->import('CatalogEvents');
  36.         $this->import('TemplateHelper');
  37.         $this->import('SQLQueryHelper');
  38.         $this->import('SQLQueryBuilder');
  39.         $this->import('CatalogFieldBuilder');
  40.         $this->import('I18nCatalogTranslator');
  41.         $this->import('FrontendEditingPermission');
  42.     }
  43.     public function initialize()
  44.     {
  45.         $this->objMainTemplate $this->objMainTemplate ?? new \stdClass();
  46.         global $objPage;
  47.         $this->setOptions();
  48.         $this->strTimeFormat $objPage->timeFormat ?? \Config::get('timeFormat');
  49.         $this->strDateFormat $objPage->dateFormat ?? \Config::get('dateFormat');
  50.         $this->strDateTimeFormat $objPage->datimFormat ?? \Config::get('datimFormat');
  51.         $this->I18nCatalogTranslator->initialize();
  52.         if (!$this->catalogTablename) return null;
  53.         $this->CatalogFieldBuilder->initialize($this->catalogTablename);
  54.         $this->arrCatalog $this->CatalogFieldBuilder->getCatalog();
  55.         $this->arrCatalogFields $this->CatalogFieldBuilder->getCatalogFields(false$this);
  56.         if (!empty($this->arrCatalogFields) && is_array($this->arrCatalogFields)) {
  57.             foreach ($this->arrCatalogFields as $strID => $arrField) {
  58.                 if (!$arrField['fieldname'] || !$arrField['type']) continue;
  59.                 $arrFieldLabels $this->I18nCatalogTranslator->get('field'$arrField['fieldname'], ['table' => $this->catalogTablename'title' => $arrField['title'], 'description' => $arrField['description'] ?? '']);
  60.                 $this->arrCatalogFields[$strID]['title'] = $arrFieldLabels[0];
  61.                 $this->arrCatalogFields[$strID]['description'] = $arrFieldLabels[1];
  62.                 if (in_array($arrField['type'], ['map''message'])) {
  63.                     $this->arrCatalogStaticFields[] = $strID;
  64.                 }
  65.                 $this->setPreviewEntityFields($arrField['fieldname'], $this->arrCatalogFields[$strID]);
  66.             }
  67.         }
  68.         $this->rebuildCatalogFieldIndexes();
  69.         $this->arrPage $objPage->row();
  70.         $this->arrMasterPage $this->arrPage;
  71.         $this->arrFrontendEditingPage $this->arrPage;
  72.         if ($this->catalogUseViewPage && $this->catalogViewPage !== '0') {
  73.             $this->arrViewPage $this->getPageModel($this->catalogViewPage);
  74.         }
  75.         if ($this->catalogUseMasterPage && $this->catalogMasterPage !== '0') {
  76.             $this->arrMasterPage $this->getPageModel($this->catalogMasterPage);
  77.         }
  78.         if ($this->catalogUseFrontendEditingViewPage && $this->catalogFrontendEditingViewPage !== '0') {
  79.             $this->arrFrontendEditingPage $this->getPageModel($this->catalogFrontendEditingViewPage);
  80.         }
  81.         if ($this->catalogUseMap && $this->strMode == 'view') {
  82.             $this->arrCatalogMapViewOptions Map::getMapViewOptions([
  83.                 'id' => 'map_' $this->id,
  84.                 'lat' => $this->catalogMapLat,
  85.                 'lng' => $this->catalogMapLng,
  86.                 'mapZoom' => $this->catalogMapZoom,
  87.                 'mapType' => $this->catalogMapType,
  88.                 'mapStyle' => \StringUtil::decodeEntities($this->catalogMapStyle),
  89.                 'mapMarker' => $this->catalogMapMarker,
  90.                 'addMapInfoBox' => $this->catalogAddMapInfoBox,
  91.                 'mapScrollWheel' => $this->catalogMapScrollWheel
  92.             ]);
  93.             $this->blnMapViewMode true;
  94.             $this->blnGoogleMapScript true;
  95.             $this->strTemplate $this->catalogMapTemplate;
  96.         }
  97.         $this->catalogOrderBy Toolkit::deserialize($this->catalogOrderBy);
  98.         $this->catalogDownloads Toolkit::deserialize($this->catalogDownloads);
  99.         $this->catalogTaxonomies Toolkit::deserialize($this->catalogTaxonomies);
  100.         $this->catalogJoinFields Toolkit::parseStringToArray($this->catalogJoinFields);
  101.         $this->catalogItemOperations Toolkit::deserialize($this->catalogItemOperations);
  102.         $this->catalogJoinCTables Toolkit::parseStringToArray($this->catalogJoinCTables);
  103.         $this->catalogRelatedChildTables Toolkit::deserialize($this->catalogRelatedChildTables);
  104.         $this->catalogExcludeArrayOptions Toolkit::deserialize($this->catalogExcludeArrayOptions);
  105.         $this->catalogPreventFieldFromFastMode Toolkit::deserialize($this->catalogPreventFieldFromFastMode);
  106.         $this->setRelatedTables();
  107.         if ($objPage->catalogRoutingTable && $objPage->catalogRoutingTable !== $this->catalogTablename) {
  108.             $objPage->catalogUseRouting '';
  109.         }
  110.         if ($objPage->catalogUseRouting && $objPage->catalogRouting && !\Config::get('CTLG_IGNORE_LIST_ROUTING')) {
  111.             $this->arrRoutingParameter Toolkit::getRoutingParameter($objPage->catalogRouting);
  112.         }
  113.         if (empty($this->arrRoutingParameter) && $this->catalogUseMasterPage) {
  114.             if ($this->arrMasterPage['catalogUseRouting']) {
  115.                 $this->arrRoutingParameter Toolkit::getRoutingParameter($this->arrMasterPage['catalogRouting']);
  116.             }
  117.         }
  118.         if ($this->enableTableView && $this->strMode == 'view') {
  119.             $this->strTemplate $this->catalogTableBodyViewTemplate;
  120.             $this->catalogActiveTableColumns $this->setActiveTableColumns();
  121.             $this->objMainTemplate->activeTableColumns $this->catalogActiveTableColumns ?: [];
  122.             $this->objMainTemplate->hasRelations = (bool)$this->catalogUseRelation;
  123.             $this->objMainTemplate->hasDownloads = (bool)$this->catalogUseDownloads;
  124.             $this->objMainTemplate->readMoreColumnTitle $GLOBALS['TL_LANG']['MSC']['CATALOG_MANAGER']['detailLink'];
  125.             $this->objMainTemplate->sharingButtonsColumnTitle $GLOBALS['TL_LANG']['MSC']['CATALOG_MANAGER']['sharing'];
  126.             $this->objMainTemplate->downloadsColumnTitle $GLOBALS['TL_LANG']['MSC']['CATALOG_MANAGER']['downloadLinks'];
  127.             $this->objMainTemplate->relationsColumnTitle $GLOBALS['TL_LANG']['MSC']['CATALOG_MANAGER']['relationsLinks'];
  128.             $this->objMainTemplate->operationsColumnTitle $GLOBALS['TL_LANG']['MSC']['CATALOG_MANAGER']['operationsLinks'];
  129.         }
  130.         $this->blnShowAsGroup $this->catalogGroupBy && $this->strMode == 'view';
  131.         $this->objMainTemplate->timeFormat $this->strTimeFormat;
  132.         $this->objMainTemplate->dateFormat $this->strDateFormat;
  133.         $this->objMainTemplate->catalogFields $this->arrCatalogFields;
  134.         $this->objMainTemplate->dateTimeFormat $this->strDateTimeFormat;
  135.         $this->objMainTemplate->catalogEntityFields $this->arrEntityFields;
  136.         $this->objMainTemplate->mapProtected \Config::get('catalogMapProtected');
  137.         $this->objMainTemplate->mapPrivacyText \Controller::replaceInsertTags(\Config::get('catalogMapPrivacyText'));
  138.         $this->objMainTemplate->mapPrivacyButtonText \Controller::replaceInsertTags((\Config::get('catalogMapPrivacyButtonText') ?: $GLOBALS['TL_LANG']['MSC']['googleMapPrivacyAcceptText']));
  139.         $this->FrontendEditingPermission->blnDisablePermissions $this->catalogEnableFrontendPermission false true;
  140.         if (!$this->FrontendEditingPermission->blnDisablePermissions) {
  141.             $this->FrontendEditingPermission->initialize();
  142.         }
  143.         if ($this->catalogUseSocialSharingButtons) {
  144.             $this->import('SocialSharingButtons');
  145.             $blnDefaultTheme $this->catalogDisableSocialSharingCSS false true;
  146.             $arrSocialSharingButtons Toolkit::deserialize($this->catalogSocialSharingButtons);
  147.             $this->SocialSharingButtons->initialize($arrSocialSharingButtons$this->catalogSocialSharingTemplate$blnDefaultTheme, [
  148.                 'catalogSocialSharingCssID' => $this->catalogSocialSharingCssID,
  149.                 'catalogSocialSharingHeadline' => $this->catalogSocialSharingHeadline
  150.             ]);
  151.         }
  152.         if (\Input::get('toggleVisibility' $this->id)) {
  153.             $this->toggleVisibility();
  154.         }
  155.         if (isset($GLOBALS['TL_HOOKS']['catalogManagerInitializeView']) && is_array($GLOBALS['TL_HOOKS']['catalogManagerInitializeView'])) {
  156.             foreach ($GLOBALS['TL_HOOKS']['catalogManagerInitializeView'] as $arrCallback) {
  157.                 if (is_array($arrCallback)) {
  158.                     $this->import($arrCallback[0]);
  159.                     $this->{$arrCallback[0]}->{$arrCallback[1]}($this);
  160.                 }
  161.             }
  162.         }
  163.         $this->setHasOperationsFlag();
  164.     }
  165.     protected function toggleVisibility()
  166.     {
  167.         $strId \Input::get('toggleVisibility' $this->id);
  168.         if ($this->catalogTablename && $this->SQLQueryHelper->SQLQueryBuilder->Database->fieldExists('invisible'$this->catalogTablename)) {
  169.             $objEntity $this->SQLQueryHelper->SQLQueryBuilder->Database->prepare('SELECT invisible FROM ' $this->catalogTablename ' WHERE id = ?')->limit(1)->execute($strId);
  170.             $strValue $objEntity->invisible '' '1';
  171.             $dteTime \Date::floorToMinute();
  172.             $arrValues = [
  173.                 'tstamp' => $dteTime,
  174.                 'invisible' => $strValue
  175.             ];
  176.             $this->SQLQueryHelper->SQLQueryBuilder->Database->prepare('UPDATE ' $this->catalogTablename ' %s WHERE id = ?')->set($arrValues)->execute($strId);
  177.             $arrData = [
  178.                 'id' => $strId,
  179.                 'row' => $arrValues,
  180.                 'table' => $this->catalogTablename,
  181.             ];
  182.             $this->CatalogEvents->addEventListener('update'$arrData$this);
  183.         }
  184.     }
  185.     public function showAsGroup()
  186.     {
  187.         return $this->blnShowAsGroup;
  188.     }
  189.     public function getHasOperationFlag()
  190.     {
  191.         return $this->blnHasOperations;
  192.     }
  193.     public function setActiveTableColumns()
  194.     {
  195.         $this->catalogActiveTableColumns Toolkit::deserialize($this->catalogActiveTableColumnstrue);
  196.         if (empty($this->catalogActiveTableColumns)) {
  197.             $this->catalogActiveTableColumns array_keys($this->arrCatalogFields);
  198.         }
  199.         foreach ($this->catalogActiveTableColumns as $strIndex => $strActiveTableColumn) {
  200.             $arrField $this->arrCatalogFields[$strActiveTableColumn];
  201.             if (is_array($arrField)) {
  202.                 if ($arrField['type'] == 'upload' && ($arrField['useArrayFormat'] ?? false)) {
  203.                     unset($this->catalogActiveTableColumns[$strIndex]);
  204.                 }
  205.             }
  206.         }
  207.         return $this->catalogActiveTableColumns;
  208.     }
  209.     protected function setPreviewEntityFields($strFieldname$arrField)
  210.     {
  211.         if (in_array($strFieldname, ['title''alias''id''pid''sorting''tstamp'])) {
  212.             return null;
  213.         }
  214.         if ($arrField['type'] == 'dbColumn') {
  215.             return null;
  216.         }
  217.         if ($arrField['type'] == 'upload' && ($arrField['useArrayFormat'] ?? false)) {
  218.             return null;
  219.         }
  220.         $this->arrEntityFields[$strFieldname] = $arrField;
  221.     }
  222.     protected function rebuildCatalogFieldIndexes()
  223.     {
  224.         $arrReturn = [];
  225.         if (!empty($this->arrCatalogFields) && is_array($this->arrCatalogFields)) {
  226.             foreach ($this->arrCatalogFields as $arrCatalogField) {
  227.                 if (!$arrCatalogField['fieldname']) continue;
  228.                 $arrReturn[$arrCatalogField['fieldname']] = $arrCatalogField;
  229.             }
  230.         }
  231.         $this->arrCatalogFields $arrReturn;
  232.     }
  233.     public function getMapViewOptions()
  234.     {
  235.         return $this->arrCatalogMapViewOptions;
  236.     }
  237.     public function getCatalogView($arrQuery)
  238.     {
  239.         global $objPage;
  240.         $this->catalogOffset = (int)$this->catalogOffset;
  241.         $blnActive $this->catalogActiveParameters false true;
  242.         $intOffset $this->catalogOffset;
  243.         $strPageID 'page_e' $this->id;
  244.         $intPerPage intval($this->catalogPerPage);
  245.         $intPagination intval(\Input::get($strPageID));
  246.         $arrQuery['table'] = $this->catalogTablename;
  247.         $arrQuery['joins'] = [];
  248.         $arrTaxonomies = [];
  249.         if (!$this->catalogTablename || !$this->SQLQueryBuilder->tableExist($this->catalogTablename)) return '';
  250.         if (!empty($this->catalogJoinFields) || is_array($this->catalogJoinFields)) {
  251.             $this->prepareJoinData($arrQuery['joins']);
  252.         }
  253.         if ($this->catalogJoinParentTable && $this->arrCatalog['pTable']) {
  254.             $this->preparePTableJoinData($arrQuery['joins']);
  255.         }
  256.         if (in_array($this->strMode, ['view''master']) && !empty($this->catalogTaxonomies['query']) && is_array($this->catalogTaxonomies['query']) && $this->catalogUseTaxonomies) {
  257.             $arrTaxonomies Toolkit::parseQueries($this->catalogTaxonomies['query']);
  258.         }
  259.         array_insert($arrQuery['where'], 0$arrTaxonomies);
  260.         if ($this->hasVisibility()) {
  261.             $dteTime \Date::floorToMinute();
  262.             $arrQuery['where'][] = [
  263.                 'field' => 'tstamp',
  264.                 'operator' => 'gt',
  265.                 'value' => 0
  266.             ];
  267.             $arrQuery['where'][] = [
  268.                 [
  269.                     'value' => '',
  270.                     'field' => 'start',
  271.                     'operator' => 'equal'
  272.                 ],
  273.                 [
  274.                     'field' => 'start',
  275.                     'operator' => 'lte',
  276.                     'value' => $dteTime
  277.                 ]
  278.             ];
  279.             $arrQuery['where'][] = [
  280.                 [
  281.                     'value' => '',
  282.                     'field' => 'stop',
  283.                     'operator' => 'equal'
  284.                 ],
  285.                 [
  286.                     'field' => 'stop',
  287.                     'operator' => 'gt',
  288.                     'value' => $dteTime
  289.                 ]
  290.             ];
  291.             $arrQuery['where'][] = [
  292.                 'field' => 'invisible',
  293.                 'operator' => 'not',
  294.                 'value' => '1'
  295.             ];
  296.         }
  297.         if ($this->catalogUseRadiusSearch && $this->strMode == 'view') {
  298.             $arrRSValues = [];
  299.             $strDistance $this->CatalogInput->getActiveValue('rs_dstnc');
  300.             $arrRSAttributes = ['rs_cty''rs_strt''rs_pstl''rs_cntry''rs_strtn'];
  301.             if (Toolkit::isEmpty($strDistance) || is_array($strDistance)) {
  302.                 $strDistance '50';
  303.             }
  304.             foreach ($arrRSAttributes as $strSRAttribute) {
  305.                 $strValue $this->CatalogInput->getActiveValue($strSRAttribute);
  306.                 if (!Toolkit::isEmpty($strValue) && is_string($strValue)) {
  307.                     $arrRSValues[$strSRAttribute] = $strValue;
  308.                 }
  309.             }
  310.             if (!empty($arrRSValues) && is_array($arrRSValues)) {
  311.                 if (!$arrRSValues['rs_cntry'] && $this->catalogRadioSearchCountry) {
  312.                     $arrRSValues['rs_cntry'] = $this->catalogRadioSearchCountry;
  313.                 }
  314.                 $objGeoCoding = new GeoCoding();
  315.                 $objGeoCoding->setCity($arrRSValues['rs_cty']);
  316.                 $objGeoCoding->setStreet($arrRSValues['rs_strt']);
  317.                 $objGeoCoding->setPostal($arrRSValues['rs_pstl']);
  318.                 $objGeoCoding->setCountry($arrRSValues['rs_cntry']);
  319.                 $objGeoCoding->setStreetNumber($arrRSValues['rs_strtn']);
  320.                 $arrCords $objGeoCoding->getCords('''en'true);
  321.                 if ($arrCords['lat'] && $arrCords['lng']) {
  322.                     $arrQuery['distance'] = [
  323.                         'value' => $strDistance,
  324.                         'latCord' => $arrCords['lat'],
  325.                         'lngCord' => $arrCords['lng'],
  326.                         'latField' => $this->catalogFieldLat,
  327.                         'lngField' => $this->catalogFieldLng
  328.                     ];
  329.                     $this->arrCatalogMapViewOptions['lat'] = $arrCords['lat'];
  330.                     $this->arrCatalogMapViewOptions['lng'] = $arrCords['lng'];
  331.                 }
  332.             }
  333.             if (!isset($arrQuery['distance']) && $this->CatalogInput->getActiveValue('_latitude') && $this->CatalogInput->getActiveValue('_longitude')) {
  334.                 $arrQuery['distance'] = [
  335.                     'value' => $strDistance,
  336.                     'latCord' => $this->CatalogInput->getActiveValue('_latitude'),
  337.                     'lngCord' => $this->CatalogInput->getActiveValue('_longitude'),
  338.                     'latField' => $this->catalogFieldLat,
  339.                     'lngField' => $this->catalogFieldLng
  340.                 ];
  341.             }
  342.         }
  343.         if (is_array($this->catalogOrderBy)) {
  344.             $this->setOrderByParameters();
  345.             if (!empty($this->catalogOrderBy)) {
  346.                 foreach ($this->catalogOrderBy as $arrOrderBy) {
  347.                     if ($arrOrderBy['key'] && $arrOrderBy['value']) {
  348.                         $arrQuery['orderBy'][] = [
  349.                             'field' => $arrOrderBy['key'],
  350.                             'order' => $arrOrderBy['value']
  351.                         ];
  352.                     }
  353.                 }
  354.             }
  355.         }
  356.         if ($this->catalogEnableParentFilter) {
  357.             if (\Input::get('pid')) {
  358.                 $arrQuery['where'][] = [
  359.                     'field' => 'pid',
  360.                     'operator' => 'equal',
  361.                     'value' => \Input::get('pid')
  362.                 ];
  363.             }
  364.         }
  365.         if (isset($GLOBALS['TL_HOOKS']['catalogManagerViewQuery']) && is_array($GLOBALS['TL_HOOKS']['catalogManagerViewQuery'])) {
  366.             foreach ($GLOBALS['TL_HOOKS']['catalogManagerViewQuery'] as $arrCallback) {
  367.                 if (is_array($arrCallback)) {
  368.                     $this->import($arrCallback[0]);
  369.                     $arrQuery $this->{$arrCallback[0]}->{$arrCallback[1]}($arrQuery$this);
  370.                 }
  371.             }
  372.         }
  373.         if ($this->catalogActiveParameters) {
  374.             $arrActiveParameterFields explode(','$this->catalogActiveParameters);
  375.             foreach ($arrActiveParameterFields as $strFieldname) {
  376.                 if ($this->CatalogInput->getActiveValue($strFieldname) !== '' && $this->CatalogInput->getActiveValue($strFieldname) !== null) {
  377.                     $blnActive true;
  378.                     break;
  379.                 }
  380.             }
  381.         }
  382.         if (!$blnActive) {
  383.             if ($this->blnGoogleMapScript) {
  384.                 $GLOBALS['TL_HEAD']['CatalogManagerGoogleMaps'] = Map::generateGoogleMapJSInitializer();
  385.             }
  386.             if ($this->catalogUseArray || $this->blnShowAsGroup) {
  387.                 return [];
  388.             }
  389.             return '';
  390.         }
  391.         $intTotal $this->SQLQueryBuilder->execute($arrQuery)->count();
  392.         if ($this->strMode == 'view') {
  393.             $arrQuery['pagination'] = [
  394.                 'limit' => $this->catalogPerPage,
  395.                 'offset' => $this->catalogOffset
  396.             ];
  397.         }
  398.         if ($this->catalogOffset$intTotal -= $intOffset;
  399.         if (\Input::get($strPageID) && $this->catalogAddPagination) {
  400.             $intOffset $intPagination;
  401.             if ($intPerPage && $this->catalogOffset) {
  402.                 $intOffset += round($this->catalogOffset $intPerPage);
  403.             }
  404.             $arrQuery['pagination']['offset'] = ($intOffset 1) * $intPerPage;
  405.         }
  406.         $arrCatalogs = [];
  407.         $intCurrentEntity 0;
  408.         $objEntities $this->SQLQueryBuilder->execute($arrQuery);
  409.         $intNumRows $objEntities->numRows;
  410.         if ($this->strMode == 'view'$this->objMainTemplate->entityIndex = [$intNumRows$intTotal];
  411.         while ($objEntities->next()) {
  412.             $arrCatalog $objEntities->row();
  413.             $intCurrentEntity++;
  414.             $arrCatalog['useSocialSharingButtons'] = $this->catalogUseSocialSharingButtons true false;
  415.             $arrCatalog['origin'] = $arrCatalog;
  416.             if ($this->strMode === 'master') {
  417.                 $this->strMasterID $arrCatalog['id'];
  418.             }
  419.             $arrCatalog['masterUrl'] = $this->getMasterRedirect($arrCatalog$arrCatalog['alias']);
  420.             $arrCatalog['hasGoBackLink'] = $this->catalogUseViewPage && $this->catalogViewPage !== '0';
  421.             if (!empty($this->arrViewPage)) {
  422.                 $arrCatalog['goBackLink'] = $this->generateUrl($this->arrViewPage'');
  423.                 $arrCatalog['goBackLabel'] = $GLOBALS['TL_LANG']['MSC']['CATALOG_MANAGER']['back'];
  424.             }
  425.             if ($this->catalogEnableFrontendEditing) {
  426.                 $arrCatalog['operations'] = $this->generateOperations($arrCatalog['id'], $arrCatalog['alias'], $arrCatalog);
  427.             }
  428.             if ($this->catalogUseDownloads) {
  429.                 $arrCatalog['downloads'] = $this->generateDownloads($arrCatalog['id'], $arrCatalog['alias']);
  430.             }
  431.             if (!empty($arrCatalog) && is_array($arrCatalog)) {
  432.                 if ($arrCatalog['id'] && !empty($this->catalogJoinCTables)) {
  433.                     foreach ($this->catalogJoinCTables as $strTable) {
  434.                         $arrCatalog[$strTable] = $this->getChildrenByIdAndTable($arrCatalog['id'], $strTable);
  435.                     }
  436.                 }
  437.                 foreach ($arrCatalog as $strFieldname => $varValue) {
  438.                     if (isset($this->arrParseAsArray[$strFieldname])) {
  439.                         $arrCatalog[$strFieldname] = $this->getJoinedEntities($varValue$strFieldname);
  440.                         continue;
  441.                     }
  442.                     $arrCatalog[$strFieldname] = $this->parseCatalogValues($varValue$strFieldname$arrCatalog);
  443.                 }
  444.             }
  445.             if ($this->catalogUseRelation) {
  446.                 $arrCatalog['relations'] = $this->setRelatedTableLinks($arrCatalog['id']);
  447.             }
  448.             $arrCatalog['contentElements'] = '';
  449.             if (($this->strMode === 'master' || $this->catalogAddContentElements) && $this->arrCatalog['addContentElements']) {
  450.                 $objContent \ContentModel::findPublishedByPidAndTable($arrCatalog['id'], $this->catalogTablename);
  451.                 if ($objContent !== null) {
  452.                     while ($objContent->next()) {
  453.                         $arrCatalog['contentElements'] .= $this->getContentElement($objContent->current());
  454.                     }
  455.                 }
  456.             }
  457.             if (!empty($this->arrCatalogStaticFields) && is_array($this->arrCatalogStaticFields) && !$this->blnMapViewMode) {
  458.                 foreach ($this->arrCatalogStaticFields as $strID) {
  459.                     $arrField $this->arrCatalogFields[$strID];
  460.                     switch ($arrField['type']) {
  461.                         case 'map':
  462.                             if (!$this->blnGoogleMapScript$this->blnGoogleMapScript true;
  463.                             $arrCatalog[$strID] = Map::parseValue(''$arrField$arrCatalog);
  464.                             break;
  465.                         case 'message':
  466.                             $arrCatalog[$strID] = MessageInput::parseValue(''$arrField$arrCatalog);
  467.                             break;
  468.                     }
  469.                 }
  470.             }
  471.             if ($this->blnMapViewMode) {
  472.                 $this->arrCatalogMapViewOptions['mapInfoBoxContent'] = Map::parseInfoBoxContent($this->catalogMapInfoBoxContent$arrCatalog);
  473.                 $this->arrCatalogMapViewOptions['locationLat'] = $arrCatalog[$this->catalogFieldLat];
  474.                 $this->arrCatalogMapViewOptions['locationLng'] = $arrCatalog[$this->catalogFieldLng];
  475.                 $arrCatalog['map'] = $this->arrCatalogMapViewOptions;
  476.             }
  477.             if ($this->strMode == 'master') {
  478.                 if ($this->catalogSEOTitle) {
  479.                         $arrCatalog[$this->catalogSEOTitle] ?? '';
  480.                     $objPage->pageTitle $arrCatalog[$this->catalogSEOTitle] ? strip_tags($arrCatalog[$this->catalogSEOTitle]) : $objPage->pageTitle;
  481.                 }
  482.                 if ($this->catalogSEODescription) {
  483.                         $arrCatalog[$this->catalogSEODescription] ?? '';
  484.                     $objPage->description $arrCatalog[$this->catalogSEODescription] ? strip_tags($arrCatalog[$this->catalogSEODescription]) : $objPage->description;
  485.                 }
  486.             }
  487.             $arrCatalog['_moduleId'] = $this->id;
  488.             $arrCatalog['timeFormat'] = $this->strTimeFormat;
  489.             $arrCatalog['dateFormat'] = $this->strDateFormat;
  490.             $arrCatalog['hasOperations'] = $this->blnHasOperations;
  491.             $arrCatalog['catalogFields'] = $this->arrCatalogFields;
  492.             $arrCatalog['dateTimeFormat'] = $this->strDateTimeFormat;
  493.             $arrCatalog['catalogEntityFields'] = $this->arrEntityFields;
  494.             $arrCatalog['readMore'] = $GLOBALS['TL_LANG']['MSC']['more'];
  495.             if ($this->strMode == 'view') {
  496.                 $intPageNumber $intPagination 1;
  497.                 $intPageOffset = !$this->catalogOffset $intPerPage $this->catalogOffset;
  498.                 $intMultiplicator $intPageNumber $intPageOffset $intPageNumber 0;
  499.                 $arrCatalog['entityIndex'] = [$intCurrentEntity $intMultiplicator$intTotal];
  500.             }
  501.             if ($this->enableTableView && $this->strMode == 'view') {
  502.                 $arrCatalog['activeTableColumns'] = $this->catalogActiveTableColumns;
  503.             }
  504.             if ($this->blnShowAsGroup && !$this->enableTableView) {
  505.                 $this->createGroups($arrCatalog[$this->catalogGroupBy]);
  506.             }
  507.             if ($arrCatalog['useSocialSharingButtons']) {
  508.                 $arrCatalog['socialSharingButtons'] = $this->SocialSharingButtons->render($arrCatalog$this->catalogSEOTitle$this->catalogSEODescription);
  509.             }
  510.             if (isset($GLOBALS['TL_HOOKS']['catalogManagerRenderCatalog']) && is_array($GLOBALS['TL_HOOKS']['catalogManagerRenderCatalog'])) {
  511.                 foreach ($GLOBALS['TL_HOOKS']['catalogManagerRenderCatalog'] as $arrCallback) {
  512.                     if (is_array($arrCallback)) {
  513.                         $this->import($arrCallback[0]);
  514.                         $this->{$arrCallback[0]}->{$arrCallback[1]}($arrCatalog$this->catalogTablename$this);
  515.                     }
  516.                 }
  517.                 if (empty($arrCatalog)) {
  518.                     continue;
  519.                 }
  520.             }
  521.             if ($this->catalogUseArray) {
  522.                 if (in_array('origin'$this->catalogExcludeArrayOptions)) unset($arrCatalog['origin']);
  523.                 if (in_array('catalogFields'$this->catalogExcludeArrayOptions)) unset($arrCatalog['catalogFields']);
  524.                 if (in_array('catalogEntityFields'$this->catalogExcludeArrayOptions)) unset($arrCatalog['catalogEntityFields']);
  525.             }
  526.             $arrCatalogs[] = $arrCatalog;
  527.         }
  528.         if ($intPerPage && $this->catalogAddPagination && $this->strMode == 'view') {
  529.             $this->objMainTemplate->pagination $this->TemplateHelper->addPagination($intTotal$intPerPage$strPageID, ($this->arrViewPage['id'] ?? ''));
  530.         }
  531.         if ($this->blnGoogleMapScript) {
  532.             $GLOBALS['TL_HEAD']['CatalogManagerGoogleMaps'] = Map::generateGoogleMapJSInitializer();
  533.         }
  534.         if ($this->catalogRandomSortingshuffle($arrCatalogs);
  535.         if ($this->catalogUseArray) return $this->getArrayValue($arrCatalogs$intNumRows);
  536.         if ($this->blnShowAsGroup && !$this->enableTableView) return $this->getGroupedValue($arrCatalogs);
  537.         return $this->getTemplateValue($arrCatalogs$intNumRows);
  538.     }
  539.     protected function setHasOperationsFlag()
  540.     {
  541.         if (!$this->catalogEnableFrontendEditing || empty($this->catalogItemOperations)) {
  542.             $this->blnHasOperations false;
  543.             return null;
  544.         }
  545.         if (isset($this->catalogItemOperations[0]) && !Toolkit::isEmpty($this->catalogItemOperations[0])) {
  546.             $this->blnHasOperations true;
  547.         }
  548.         if (count($this->catalogItemOperations) === && in_array('create'$this->catalogItemOperations)) {
  549.             $this->blnHasOperations false;
  550.         }
  551.     }
  552.     protected function getJoinedEntities($strValue$strFieldname)
  553.     {
  554.         $arrReturn = [];
  555.         $strTable $this->arrParseAsArray[$strFieldname]['onTable'];
  556.         $strField $this->arrParseAsArray[$strFieldname]['onField'];
  557.         $arrOrderBy Toolkit::parseStringToArray($this->arrCatalogFields[$strFieldname]['dbOrderBy']);
  558.         $arrQuery = [
  559.             'table' => $strTable,
  560.             'where' => [
  561.                 [
  562.                     'field' => $strField,
  563.                     'operator' => 'findInSet',
  564.                     'value' => explode(','$strValue)
  565.                 ]
  566.             ],
  567.             'orderBy' => []
  568.         ];
  569.         if (is_array($arrOrderBy) && !empty($arrOrderBy)) {
  570.             foreach ($arrOrderBy as $arrOrder) {
  571.                 $arrQuery['orderBy'][] = [
  572.                     'field' => $arrOrder['key'],
  573.                     'order' => $arrOrder['value']
  574.                 ];
  575.             }
  576.         }
  577.         if ($this->arrParseAsArray[$strFieldname]['hasVisibility']) {
  578.             $dteTime \Date::floorToMinute();
  579.             $arrQuery['where'][] = [
  580.                 'field' => 'tstamp',
  581.                 'operator' => 'gt',
  582.                 'value' => 0
  583.             ];
  584.             $arrQuery['where'][] = [
  585.                 [
  586.                     'value' => '',
  587.                     'field' => 'start',
  588.                     'operator' => 'equal'
  589.                 ],
  590.                 [
  591.                     'field' => 'start',
  592.                     'operator' => 'lte',
  593.                     'value' => $dteTime
  594.                 ]
  595.             ];
  596.             $arrQuery['where'][] = [
  597.                 [
  598.                     'value' => '',
  599.                     'field' => 'stop',
  600.                     'operator' => 'equal'
  601.                 ],
  602.                 [
  603.                     'field' => 'stop',
  604.                     'operator' => 'gt',
  605.                     'value' => $dteTime
  606.                 ]
  607.             ];
  608.             $arrQuery['where'][] = [
  609.                 'field' => 'invisible',
  610.                 'operator' => 'not',
  611.                 'value' => '1'
  612.             ];
  613.         }
  614.         $objEntities $this->SQLQueryBuilder->execute($arrQuery);
  615.         if (!$objEntities->numRows) return $arrReturn;
  616.         while ($objEntities->next()) {
  617.             $arrReturn[] = Toolkit::parseCatalogValues($objEntities->row(), $this->arrCatalogFieldsfalse$strTable);
  618.         }
  619.         return $arrReturn;
  620.     }
  621.     public function hasVisibility()
  622.     {
  623.         if (!$this->SQLQueryHelper->SQLQueryBuilder->Database->fieldExists('invisible'$this->catalogTablename)) {
  624.             return false;
  625.         }
  626.         if ($this->catalogIgnoreVisibility) {
  627.             return false;
  628.         }
  629.         if (is_array($this->arrCatalog['operations']) && !in_array('invisible'$this->arrCatalog['operations'])) {
  630.             return false;
  631.         }
  632.         if (\BackendUser::getInstance()->id && \Input::get('preview') == '1') {
  633.             return false;
  634.         }
  635.         if (defined('BE_USER_LOGGED_IN') && BE_USER_LOGGED_IN) {
  636.             return false;
  637.         }
  638.         return true;
  639.     }
  640.     protected function createGroups($varGroupName)
  641.     {
  642.         if (is_array($varGroupName)) {
  643.             foreach ($varGroupName as $strGroup) {
  644.                 if (is_array($strGroup)) {
  645.                     $strKeyname $this->arrCatalogFields[$this->catalogGroupBy]['dbTableValue'] ?: 'title';
  646.                     $strGroup $strGroup[$strKeyname];
  647.                 }
  648.                 $this->createGroups($strGroup);
  649.             }
  650.         }
  651.         if ($varGroupName && is_string($varGroupName) && !isset($this->arrGroups[$varGroupName])) {
  652.             $this->arrGroups[$varGroupName] = [];
  653.         }
  654.     }
  655.     protected function getGroupedValue($arrCatalogs)
  656.     {
  657.         $arrIndexes = [];
  658.         foreach ($arrCatalogs as $arrCatalog) {
  659.             $varGroupName $arrCatalog[$this->catalogGroupBy];
  660.             $this->groupByValue($varGroupName$arrCatalog$arrIndexes);
  661.         }
  662.         return $this->arrGroups;
  663.     }
  664.     protected function groupByValue($varGroupName$arrCatalog, &$arrIndexes)
  665.     {
  666.         if (is_array($varGroupName)) {
  667.             foreach ($varGroupName as $strGroupName) {
  668.                 if (is_array($strGroupName)) {
  669.                     $strKeyname $this->arrCatalogFields[$this->catalogGroupBy]['dbTableValue'] ?: 'title';
  670.                     $strGroupName $strGroupName[$strKeyname];
  671.                 }
  672.                 $this->groupByValue($strGroupName$arrCatalog$arrIndexes);
  673.             }
  674.         }
  675.         if ($varGroupName && is_string($varGroupName)) {
  676.             $objTemplate = new \FrontendTemplate($this->strTemplate);
  677.             if (!$this->arrGroups[$varGroupName]) $arrIndexes[$varGroupName] = 0;
  678.             $arrCatalog['cssClass'] = $arrIndexes[$varGroupName] % ' even' ' odd';
  679.             $arrCatalog['_mainGroup'] = $varGroupName;
  680.             $objTemplate->setData($arrCatalog);
  681.             $this->arrGroups[$varGroupName][] = $objTemplate->parse();
  682.             $arrIndexes[$varGroupName]++;
  683.         }
  684.     }
  685.     protected function getTemplateValue($arrCatalogs$intNumRows)
  686.     {
  687.         $strContent '';
  688.         $objTemplate = new \FrontendTemplate($this->strTemplate);
  689.         foreach ($arrCatalogs as $intIndex => $arrCatalog) {
  690.             $arrCatalog['cssClass'] = $intIndex ' even' ' odd';
  691.             if (!$intIndex$arrCatalog['cssClass'] .= ' first';
  692.             if ($intIndex == ($intNumRows 1)) $arrCatalog['cssClass'] .= ' last';
  693.             $objTemplate->setData($arrCatalog);
  694.             $strContent .= $objTemplate->parse();
  695.         }
  696.         return $strContent;
  697.     }
  698.     protected function getArrayValue($arrCatalogs$intNumRows)
  699.     {
  700.         for ($intIndex 0$intIndex count($arrCatalogs); $intIndex++) {
  701.             $arrCatalogs[$intIndex]['cssClass'] = $intIndex ' even' ' odd';
  702.             if (!$intIndex$arrCatalogs[$intIndex]['cssClass'] .= ' first';
  703.             if ($intIndex == ($intNumRows 1)) $arrCatalogs[$intIndex]['cssClass'] .= ' last';
  704.         }
  705.         return $arrCatalogs;
  706.     }
  707.     protected function getActiveFieldsHeadline($strTemplate)
  708.     {
  709.         return sprintf($GLOBALS['TL_LANG']['MSC']['CATALOG_MANAGER']['activeFieldsHeadline'], $strTemplate);
  710.     }
  711.     protected function setOrderByParameters()
  712.     {
  713.         $strSort $this->CatalogInput->getActiveValue('sortID' $this->id);
  714.         $strOrder $this->CatalogInput->getActiveValue('orderID' $this->id);
  715.         if (Toolkit::isEmpty($strSort) || is_array($strSort)) {
  716.             $strSort '';
  717.         }
  718.         if (Toolkit::isEmpty($strOrder) || is_array($strOrder)) {
  719.             $strOrder 'DESC';
  720.         } else {
  721.             mb_strtoupper($strOrder'UTF-8');
  722.         }
  723.         if (!in_array($strOrder, ['ASC''DESC'])) {
  724.             if ($strOrder == 'RAND') {
  725.                 $this->catalogRandomSorting '1';
  726.             } else {
  727.                 $strOrder 'DESC';
  728.             }
  729.         };
  730.         if ($strSort && $this->SQLQueryHelper->SQLQueryBuilder->Database->fieldExists($strSort$this->catalogTablename)) {
  731.             $this->catalogOrderBy = [[
  732.                 'key' => $strSort,
  733.                 'value' => $strOrder
  734.             ]];
  735.         }
  736.     }
  737.     protected function getMasterRedirect($arrCatalog = [], $strAlias '')
  738.     {
  739.         if ($this->catalogDisableMasterLink) return '';
  740.         if ($this->arrCatalog['useRedirect'] && $this->arrCatalog['internalUrlColumn']) {
  741.             if ($arrCatalog[$this->arrCatalog['internalUrlColumn']]) {
  742.                 return \Controller::replaceInsertTags($arrCatalog[$this->arrCatalog['internalUrlColumn']]);
  743.             }
  744.         }
  745.         if ($this->arrCatalog['useRedirect'] && $this->arrCatalog['externalUrlColumn']) {
  746.             if ($arrCatalog[$this->arrCatalog['externalUrlColumn']]) {
  747.                 return $arrCatalog[$this->arrCatalog['externalUrlColumn']];
  748.             }
  749.         }
  750.         $strAlias $this->getAliasWithParameters($strAlias$arrCatalog);
  751.         return $this->generateUrl($this->arrMasterPage$strAlias);
  752.     }
  753.     protected function getAliasWithParameters($strAlias$arrCatalog = [])
  754.     {
  755.         if (!empty($this->arrRoutingParameter) && is_array($this->arrRoutingParameter)) {
  756.             return Toolkit::generateAliasWithRouting($strAlias$this->arrRoutingParameter$arrCatalog);
  757.         }
  758.         return $strAlias;
  759.     }
  760.     protected function isFastMode($strType ''$strFieldname '')
  761.     {
  762.         if ($this->catalogFastMode && $this->strMode == 'view' && in_array($strTypeToolkit::$arrDoNotRenderInFastMode)) {
  763.             if ($strFieldname && is_array($this->catalogPreventFieldFromFastMode) && in_array($strFieldname$this->catalogPreventFieldFromFastMode)) return false;
  764.             return true;
  765.         }
  766.         return false;
  767.     }
  768.     protected function parseCatalogValues($varValue$strFieldname, &$arrCatalog)
  769.     {
  770.         $arrField $this->arrCatalogFields[$strFieldname] ?? [];
  771.         if (empty($arrField)) {
  772.             return $varValue;
  773.         }
  774.         $strType $arrField['type'];
  775.         if (isset($arrField['_isDate']) && $arrField['_isDate'] != null && $arrField['_isDate'] === true) {
  776.             $strType 'date';
  777.         }
  778.         if (Toolkit::isEmpty($strType)) return $varValue;
  779.         if ($this->isFastMode($strType$strFieldname)) return '';
  780.         $arrImgSize \StringUtil::deserialize($this->arrOptions['imgSize']);
  781.         if (is_array($arrImgSize) && !empty(array_filter($arrImgSize))) $arrField['size'] = $this->arrOptions['imgSize'];
  782.         switch ($strType) {
  783.             case 'upload':
  784.                 if (is_null($varValue)) return ($arrField['useArrayFormat'] ?? false) ? [] : '';
  785.                 $varValue Upload::parseValue($varValue$arrField$arrCatalog);
  786.                 if (is_array($varValue) && $arrField['fileType'] == 'gallery') {
  787.                     if ($varValue['preview']) {
  788.                         $arrCatalog[$strFieldname 'Preview'] = $varValue['preview'];
  789.                     }
  790.                     return $varValue['gallery'];
  791.                 }
  792.                 return $varValue;
  793.             case 'select':
  794.                 return Select::parseValue($varValue$arrField$arrCatalog);
  795.             case 'checkbox':
  796.                 return Checkbox::parseValue($varValue$arrField$arrCatalog);
  797.             case 'radio':
  798.                 return Radio::parseValue($varValue$arrField$arrCatalog);
  799.             case 'text':
  800.                 return Text::parseValue($varValue$arrField$arrCatalog);
  801.             case 'date':
  802.                 return DateInput::parseValue($varValue$arrField$arrCatalog);
  803.             case 'number':
  804.                 return Number::parseValue($varValue$arrField$arrCatalog);
  805.             case 'textarea':
  806.                 return Textarea::parseValue($varValue$arrField$arrCatalog);
  807.             case 'dbColumn':
  808.                 return DbColumn::parseValue($varValue$arrField$arrCatalog);
  809.         }
  810.         return $varValue;
  811.     }
  812.     public function getCommentForm($strMasterID)
  813.     {
  814.         if (!in_array('comments'\ModuleLoader::getActive())) {
  815.             return null;
  816.         }
  817.         if (!$this->catalogAllowComments) {
  818.             return null;
  819.         }
  820.         $this->TemplateHelper->addComments(
  821.             $this->objMainTemplate,
  822.             [
  823.                 'template' => $this->com_template,
  824.                 'bbcode' => $this->catalogCommentBBCode,
  825.                 'perPage' => $this->catalogCommentPerPage,
  826.                 'order' => $this->catalogCommentSortOrder,
  827.                 'moderate' => $this->catalogCommentModerate,
  828.                 'requireLogin' => $this->catalogCommentRequireLogin,
  829.                 'disableCaptcha' => $this->catalogCommentDisableCaptcha
  830.             ],
  831.             $this->catalogTablename,
  832.             ($strMasterID $strMasterID '0'),
  833.             []
  834.         );
  835.     }
  836.     protected function setOptions()
  837.     {
  838.         if (!empty($this->arrOptions) && is_array($this->arrOptions)) {
  839.             foreach ($this->arrOptions as $strKey => $varValue) {
  840.                 $this->{$strKey} = $varValue;
  841.             }
  842.         }
  843.     }
  844.     protected function getPageModel($strID)
  845.     {
  846.         return $this->SQLQueryHelper->SQLQueryBuilder->execute([
  847.             'table' => 'tl_page',
  848.             'pagination' => [
  849.                 'limit' => 1,
  850.                 'offset' => 0
  851.             ],
  852.             'where' => [
  853.                 [
  854.                     'field' => 'id',
  855.                     'value' => $strID,
  856.                     'operator' => 'equal'
  857.                 ]
  858.             ]
  859.         ])->row();
  860.     }
  861.     protected function prepareJoinData(&$arrReturn)
  862.     {
  863.         foreach ($this->catalogJoinFields as $strFieldJoinID) {
  864.             $arrRelatedJoinData = [];
  865.             if (!$this->arrCatalogFields[$strFieldJoinID]) {
  866.                 continue;
  867.             }
  868.             $arrRelatedJoinData['multiple'] = false;
  869.             $arrRelatedJoinData['table'] = $this->catalogTablename;
  870.             $arrRelatedJoinData['field'] = $this->arrCatalogFields[$strFieldJoinID]['fieldname'];
  871.             $arrRelatedJoinData['onTable'] = $this->arrCatalogFields[$strFieldJoinID]['dbTable'];
  872.             $arrRelatedJoinData['onField'] = $this->arrCatalogFields[$strFieldJoinID]['dbTableKey'];
  873.             if ($this->arrCatalogFields[$strFieldJoinID]['multiple'] || $this->arrCatalogFields[$strFieldJoinID]['type'] == 'checkbox') {
  874.                 $arrRelatedJoinData['multiple'] = true;
  875.             }
  876.             $this->arrCatalogFields $this->SQLQueryHelper->getCatalogFieldsByCatalogTablename($arrRelatedJoinData['onTable'], $this->arrCatalogFieldstrue$this->arrCatalogStaticFields);
  877.             if ($arrRelatedJoinData['multiple'] && $this->catalogJoinAsArray) {
  878.                 $objCatalogFieldBuilder = new CatalogFieldBuilder();
  879.                 $objCatalogFieldBuilder->initialize($arrRelatedJoinData['onTable']);
  880.                 $arrCatalog $objCatalogFieldBuilder->getCatalog();
  881.                 $arrRelatedJoinData['hasVisibility'] = in_array('invisible'$arrCatalog['operations']);
  882.                 $this->arrParseAsArray[$arrRelatedJoinData['field']] = $arrRelatedJoinData;
  883.                 continue;
  884.             }
  885.             $arrReturn[] = $arrRelatedJoinData;
  886.         }
  887.     }
  888.     protected function getChildrenByIdAndTable($strId$strTable)
  889.     {
  890.         $objFieldBuilder = new CatalogFieldBuilder();
  891.         $objFieldBuilder->initialize($strTable);
  892.         $arrReturn = [];
  893.         $arrCatalog $objFieldBuilder->getCatalog();
  894.         $arrFields $objFieldBuilder->getCatalogFields(truenull);
  895.         $arrQuery = [
  896.             'table' => $strTable,
  897.             'where' => [
  898.                 [
  899.                     'field' => 'pid',
  900.                     'value' => $strId,
  901.                     'operator' => 'equal'
  902.                 ]
  903.             ]
  904.         ];
  905.         if (in_array('invisible'$arrCatalog['operations'])) {
  906.             $dteTime \Date::floorToMinute();
  907.             $arrQuery['where'][] = [
  908.                 'field' => 'tstamp',
  909.                 'operator' => 'gt',
  910.                 'value' => 0
  911.             ];
  912.             $arrQuery['where'][] = [
  913.                 [
  914.                     'value' => '',
  915.                     'field' => 'start',
  916.                     'operator' => 'equal'
  917.                 ],
  918.                 [
  919.                     'field' => 'start',
  920.                     'operator' => 'lte',
  921.                     'value' => $dteTime
  922.                 ]
  923.             ];
  924.             $arrQuery['where'][] = [
  925.                 [
  926.                     'value' => '',
  927.                     'field' => 'stop',
  928.                     'operator' => 'equal'
  929.                 ],
  930.                 [
  931.                     'field' => 'stop',
  932.                     'operator' => 'gt',
  933.                     'value' => $dteTime
  934.                 ]
  935.             ];
  936.             $arrQuery['where'][] = [
  937.                 'field' => 'invisible',
  938.                 'operator' => 'not',
  939.                 'value' => '1'
  940.             ];
  941.         }
  942.         if (!empty($arrCatalog['sortingFields'])) {
  943.             $numFlag = (int)$arrCatalog['flag'] ?: 1;
  944.             foreach ($arrCatalog['sortingFields'] as $strSortingField) {
  945.                 $arrQuery['orderBy'][] = [
  946.                     'field' => $strSortingField,
  947.                     'order' => ($numFlag == 0) ? 'DESC' 'ASC'
  948.                 ];
  949.             }
  950.         }
  951.         $objEntities $this->SQLQueryBuilder->execute($arrQuery);
  952.         if (!$objEntities->numRows) {
  953.             return $arrReturn;
  954.         }
  955.         while ($objEntities->next()) {
  956.             $arrReturn[] = Toolkit::parseCatalogValues($objEntities->row(), $arrFields);
  957.         }
  958.         return $arrReturn;
  959.     }
  960.     protected function generateUrl($objPage$strAlias)
  961.     {
  962.         if ($objPage == null) return '';
  963.         return $this->generateFrontendUrl($objPage, ($strAlias '/' $strAlias ''));
  964.     }
  965.     protected function generateDownloads($strID$strAlias '')
  966.     {
  967.         $arrReturn = [];
  968.         $strConnector '?';
  969.         $strUrl ampersand(\Environment::get('indexFreeRequest'));
  970.         if (strpos($strUrl$strConnector) !== false) {
  971.             $strConnector '&';
  972.         }
  973.         if (!empty($this->catalogDownloads) && is_array($this->catalogDownloads)) {
  974.             foreach ($this->catalogDownloads as $strDownload) {
  975.                 $arrReturn[$strDownload] = [
  976.                     'href' => $strUrl $strConnector $strDownload $this->id '=' $strID,
  977.                     'title' => $GLOBALS['TL_LANG']['tl_module']['reference']['catalogDownloadTitles'][$strDownload],
  978.                     'image' => \Image::getHtml(Toolkit::getIcon($strDownload), $GLOBALS['TL_LANG']['tl_module']['reference']['catalogDownloadTitles'][$strDownload]),
  979.                     'attributes' => '',
  980.                 ];
  981.             }
  982.         }
  983.         return $arrReturn;
  984.     }
  985.     protected function generateOperations($strID$strAlias ''$arrCatalog = [])
  986.     {
  987.         $arrReturn = [];
  988.         $this->loadLanguageFile('tl_module');
  989.         if (!empty($this->catalogItemOperations) && is_array($this->catalogItemOperations)) {
  990.             $strAlias $this->getAliasWithParameters($strAlias$arrCatalog);
  991.             foreach ($this->catalogItemOperations as $strOperation) {
  992.                 if (!$strOperation || $strOperation == 'create') continue;
  993.                 if (!$this->FrontendEditingPermission->hasPermission(($strOperation === 'copy' 'create' $strOperation), $this->catalogTablename)) {
  994.                     continue;
  995.                 }
  996.                 $strActFragment sprintf('?act%s=%s&id%s=%s'$this->id$strOperation$this->id$strID);
  997.                 if ($this->arrCatalog['pTable']) {
  998.                     $strActFragment .= sprintf('&amp;pid=%s', (\Input::get('pid') ? \Input::get('pid') : $arrCatalog['pid']));
  999.                 }
  1000.                 $arrReturn[$strOperation] = [
  1001.                     'class' => 'act_' $strOperation,
  1002.                     'href' => $this->generateUrl($this->arrFrontendEditingPage$strAlias) . $strActFragment,
  1003.                     'title' => $GLOBALS['TL_LANG']['tl_module']['reference']['catalogItemOperations'][$strOperation],
  1004.                     'image' => \Image::getHtml(Toolkit::getIcon($strOperation), $GLOBALS['TL_LANG']['tl_module']['reference']['catalogItemOperations'][$strOperation]),
  1005.                     'attributes' => $strOperation === 'delete' 'onclick="if(!confirm(\'' sprintf($GLOBALS['TL_LANG']['MSC']['deleteConfirm'], $strID) . '\'))return false;"' '',
  1006.                 ];
  1007.             }
  1008.         }
  1009.         if (empty($arrReturn)) $this->blnHasOperations false;
  1010.         return $arrReturn;
  1011.     }
  1012.     public function getCreateOperation()
  1013.     {
  1014.         $strPTableFragment '';
  1015.         $this->loadLanguageFile('tl_module');
  1016.         if (!$this->catalogEnableFrontendEditing) return [];
  1017.         if (!$this->FrontendEditingPermission->hasPermission('create'$this->catalogTablename)) {
  1018.             return [];
  1019.         }
  1020.         if (empty($this->catalogItemOperations) || !in_array('create'$this->catalogItemOperations)) {
  1021.             return [];
  1022.         }
  1023.         if ($this->arrCatalog['pTable'] && !\Input::get('pid')) {
  1024.             return [];
  1025.         }
  1026.         if ($this->arrCatalog['pTable']) {
  1027.             $strPTableFragment sprintf('&amp;pid=%s'\Input::get('pid'));
  1028.         }
  1029.         return [
  1030.             'attributes' => '',
  1031.             'title' => $GLOBALS['TL_LANG']['tl_module']['reference']['catalogItemOperations']['create'],
  1032.             'href' => $this->generateUrl($this->arrFrontendEditingPage'') . sprintf('?act%s=create%s'$this->id$strPTableFragment),
  1033.             'image' => \Image::getHtml(Toolkit::getIcon('new'), $GLOBALS['TL_LANG']['tl_module']['reference']['catalogItemOperations']['create'])
  1034.         ];
  1035.     }
  1036.     protected function preparePTableJoinData(&$arrReturn)
  1037.     {
  1038.         $this->arrCatalogFields $this->SQLQueryHelper->getCatalogFieldsByCatalogTablename($this->arrCatalog['pTable'], $this->arrCatalogFieldstrue$this->arrCatalogStaticFields);
  1039.         $arrReturn[] = [
  1040.             'field' => 'pid',
  1041.             'onField' => 'id',
  1042.             'multiple' => false,
  1043.             'table' => $this->catalogTablename,
  1044.             'onTable' => $this->arrCatalog['pTable']
  1045.         ];
  1046.     }
  1047.     protected function setRelatedTableLinks($strID)
  1048.     {
  1049.         foreach ($this->arrRelatedTables as $strTablename => $arrRelatedTable) {
  1050.             $strUrl $this->arrRelatedTables[$strTablename]['url'];
  1051.             $strSuffix sprintf('?pid=%s'$strID);
  1052.             $this->arrRelatedTables[$strTablename]['href'] = $strUrl $strSuffix;
  1053.         }
  1054.         return $this->arrRelatedTables;
  1055.     }
  1056.     protected function setRelatedTables()
  1057.     {
  1058.         if (!empty($this->catalogRelatedChildTables) && is_array($this->catalogRelatedChildTables)) {
  1059.             foreach ($this->catalogRelatedChildTables as $arrRelatedTable) {
  1060.                 if (!is_array($arrRelatedTable)) continue;
  1061.                 if (Toolkit::isEmpty($arrRelatedTable['active'])) continue;
  1062.                 $arrTableData = [];
  1063.                 $objCatalog $this->SQLQueryHelper->SQLQueryBuilder->Database->prepare('SELECT * FROM tl_catalog WHERE tablename = ?')->limit(1)->execute($arrRelatedTable['table']);
  1064.                 if (!$objCatalog->numRows) continue;
  1065.                 $arrCatalog $objCatalog->row();
  1066.                 $strTitle $this->I18nCatalogTranslator->get('module'$arrRelatedTable['table'], ['titleOnly' => true]);
  1067.                 $arrTableData['title'] = $strTitle;
  1068.                 $arrTableData['info'] = $arrCatalog['info'];
  1069.                 $arrTableData['description'] = $arrCatalog['description'];
  1070.                 $arrTableData['url'] = \Controller::replaceInsertTags($arrRelatedTable['pageURL']);
  1071.                 $arrTableData['image'] = \Image::getHtml($this->IconGetter->setCatalogIcon($arrRelatedTable['table']), $strTitle);
  1072.                 $this->arrRelatedTables[$arrRelatedTable['table']] = $arrTableData;
  1073.             }
  1074.         }
  1075.     }
  1076.     public function getCatalog()
  1077.     {
  1078.         return is_array($this->arrCatalog) && !empty($this->arrCatalog) ? $this->arrCatalog : [];
  1079.     }
  1080.     public function changeItemOperations($arrItemOperations)
  1081.     {
  1082.         $this->catalogItemOperations $arrItemOperations;
  1083.     }
  1084.     public function getItemOperations()
  1085.     {
  1086.         return $this->catalogItemOperations;
  1087.     }
  1088.     public function getCatalogFields()
  1089.     {
  1090.         return $this->arrCatalogFields;
  1091.     }
  1092. }