vendor/alnv/catalog-manager/library/alnv/OptionsGetter.php line 189

Open in your IDE?
  1. <?php
  2. namespace CatalogManager;
  3. use Contao\StringUtil;
  4. class OptionsGetter extends CatalogController
  5. {
  6.     protected $strModuleID;
  7.     protected $arrCache = [];
  8.     protected $arrField = [];
  9.     protected $arrQueries = [];
  10.     protected $arrCatalog = [];
  11.     protected $strActiveTable '';
  12.     protected $arrActiveEntity = [];
  13.     protected $arrCatalogFields = [];
  14.     public function __construct($arrField$strModuleID ''$arrQueries = [])
  15.     {
  16.         parent::__construct();
  17.         $this->arrField $arrField;
  18.         $this->strModuleID $strModuleID;
  19.         foreach ($arrQueries as $strQuery) if (!Toolkit::isEmpty($strQuery)) $this->arrQueries[] = $strQuery;
  20.         $this->import('CatalogInput');
  21.         $this->import('OrderByHelper');
  22.         $this->import('SQLQueryHelper');
  23.         $this->import('SQLQueryBuilder');
  24.         $this->import('CatalogDcExtractor');
  25.         $this->import('I18nCatalogTranslator');
  26.     }
  27.     public function isForeignKey()
  28.     {
  29.         if (isset($this->arrField['optionsType']) && $this->arrField['optionsType'] && $this->arrField['optionsType'] == 'useForeignKey') {
  30.             return true;
  31.         }
  32.         return false;
  33.     }
  34.     public function getForeignKey()
  35.     {
  36.         return $this->setForeignKey();
  37.     }
  38.     public function getOptions()
  39.     {
  40.         switch ($this->arrField['optionsType'] ?? '') {
  41.             case 'useOptions':
  42.                 return $this->getKeyValueOptions();
  43.             case 'useForeignKey':
  44.                 $this->arrField['dbTableKey'] = 'id';
  45.                 return $this->getDbOptions();
  46.             case 'useDbOptions':
  47.                 return $this->getDbOptions();
  48.             case 'useActiveDbOptions':
  49.                 return $this->getActiveDbOptions();
  50.         }
  51.         if (!isset($this->arrField['optionsType']) && in_array($this->arrField['fieldname'], ['country''countries']) && in_array($this->arrField['type'], ['radio''select''checkbox'])) {
  52.             return \System::getCountries();
  53.         }
  54.         return [];
  55.     }
  56.     public function getTableEntities()
  57.     {
  58.         switch ($this->arrField['optionsType'] ?? '') {
  59.             case 'useDbOptions':
  60.             case 'useForeignKey':
  61.                 if (!$this->arrField['dbTable'] || !$this->arrField['dbTableKey'] || !$this->arrField['dbTableValue']) {
  62.                     return null;
  63.                 }
  64.                 if (!$this->SQLQueryHelper->SQLQueryBuilder->Database->tableExists($this->arrField['dbTable'])) {
  65.                     return null;
  66.                 }
  67.                 if (!$this->SQLQueryHelper->SQLQueryBuilder->Database->fieldExists($this->arrField['dbTableKey'], $this->arrField['dbTable'])) {
  68.                     return null;
  69.                 }
  70.                 if (!$this->SQLQueryHelper->SQLQueryBuilder->Database->fieldExists($this->arrField['dbTableValue'], $this->arrField['dbTable'])) {
  71.                     return null;
  72.                 }
  73.                 return $this->getResults(true);
  74.             case 'useActiveDbOptions':
  75.                 $strDbColumn $this->arrField['dbColumn'];
  76.                 if (!$this->arrField['dbTable'] || !$strDbColumn) {
  77.                     return null;
  78.                 }
  79.                 if (!$this->SQLQueryHelper->SQLQueryBuilder->Database->tableExists($this->arrField['dbTable'])) {
  80.                     return null;
  81.                 }
  82.                 if (!$this->SQLQueryHelper->SQLQueryBuilder->Database->fieldExists($strDbColumn$this->arrField['dbTable'])) {
  83.                     return null;
  84.                 }
  85.                 return $this->getResults(false);
  86.         }
  87.         return null;
  88.     }
  89.     protected function setValueToOption(&$arrOptions$strValue$strLabel ''$strTable '')
  90.     {
  91.         $strKey $strValue;
  92.         $strKey \StringUtil::decodeEntities($strKey);
  93.         $strText $strLabel ?: $strKey;
  94.         if (isset($this->arrField['dbParseDate']) && $this->arrField['dbParseDate']) {
  95.             $strFormat $this->arrField['dbMonthBeginFormat'] ?: 'F Y';
  96.             if ($this->arrField['dbDateFormat'] == 'yearBegin'$strFormat $this->arrField['dbYearBeginFormat'] ?: 'Y';
  97.             if ($this->arrField['dbDateFormat'] == 'dayBegin'$strFormat $this->arrField['dbDayBeginFormat'] ?: 'l, F Y';
  98.             $strKey DateInput::parseValue($strValue, ['rgxp' => $this->arrField['dbDateFormat']], []);
  99.             $strText \Controller::parseDate($strFormat$strValue);
  100.         } else {
  101.             $strText $this->I18nCatalogTranslator->get('option'$strKey, ['title' => $strText'table' => $strTable]);
  102.         }
  103.         if ($strKey && !in_array($strKeyarray_keys($arrOptions))) {
  104.             $arrOptions[$strKey] = $strText;
  105.         }
  106.         /*
  107.         if ($strValue && !in_array($strValue, $arrOptions)) {
  108.             $strValue = \StringUtil::decodeEntities($strValue);
  109.             $strTitle = $strValue;
  110.             if (isset($this->arrField['dbParseDate']) && $this->arrField['dbParseDate']) {
  111.                 $strFormat = $this->arrField['dbMonthBeginFormat'] ?: 'F Y';
  112.                 if ($this->arrField['dbDateFormat'] == 'yearBegin') $strFormat = $this->arrField['dbYearBeginFormat'] ?: 'Y';
  113.                 if ($this->arrField['dbDateFormat'] == 'dayBegin') $strFormat = $this->arrField['dbDayBeginFormat'] ?: 'l, F Y';
  114.                 $strValue = DateInput::parseValue($strValue, ['rgxp' => $this->arrField['dbDateFormat']], []);
  115.                 $strTitle = \Controller::parseDate($strFormat, $strValue);
  116.             } else {
  117.                 $strTitle = $this->I18nCatalogTranslator->get('option', $strTitle, ['title' => $strLabel, 'table' => $strTable]);
  118.             }
  119.             $arrOptions[$strValue] = \StringUtil::decodeEntities($strTitle);
  120.         }
  121.         */
  122.         return $arrOptions;
  123.     }
  124.     protected function parseCatalogValues($varValue$strFieldname$arrCatalog)
  125.     {
  126.         $arrField $this->arrCatalogFields[$strFieldname];
  127.         switch ($arrField['type']) {
  128.             case 'select':
  129.                 return Select::parseValue($varValue$arrField$arrCatalog);
  130.             case 'checkbox':
  131.                 return Checkbox::parseValue($varValue$arrField$arrCatalog);
  132.             case 'radio':
  133.                 return Radio::parseValue($varValue$arrField$arrCatalog);
  134.             case 'text':
  135.                 return Text::parseValue($varValue$arrField$arrCatalog);
  136.         }
  137.         return $varValue;
  138.     }
  139.     protected function getResults($blnUseValidValue false)
  140.     {
  141.         $arrSQLQuery = [
  142.             'table' => $this->arrField['dbTable']
  143.         ];
  144.         $this->getActiveTable();
  145.         $this->getActiveEntityValues();
  146.         $strOrderBy $this->getOrderBy();
  147.         $arrDbTaxonomies Toolkit::deserialize($this->arrField['dbTaxonomy']);
  148.         $arrQueries is_array($arrDbTaxonomies) && isset($arrDbTaxonomies['query']) ? $arrDbTaxonomies['query'] : [];
  149.         $arrSQLQuery['where'] = Toolkit::parseQueries($arrQueries, function ($arrQuery) use ($blnUseValidValue) {
  150.             $blnValidValue true;
  151.             $blnIgnoreEmptyValues = isset($this->arrField['dbIgnoreEmptyValues']) && $this->arrField['dbIgnoreEmptyValues'];
  152.             if ($blnIgnoreEmptyValues && in_array($arrQuery['operator'], ['isEmpty''isNotEmpty'])) $blnIgnoreEmptyValues false;
  153.             $arrQuery['value'] = $this->getParseQueryValue($arrQuery['value'], $arrQuery['operator'], $blnValidValue);
  154.             $arrQuery['allowEmptyValues'] = $blnIgnoreEmptyValues false true;
  155.             if (!$blnValidValue && $blnUseValidValue) return null;
  156.             return $arrQuery;
  157.         });
  158.         if (is_array($this->arrQueries) && !empty($this->arrQueries)) {
  159.             $arrSQLQuery['where'][] = [
  160.                 'multiple' => true,
  161.                 'operator' => 'regexp',
  162.                 'field' => $this->arrField['dbTableValue'],
  163.                 'value' => implode(','$this->arrQueries)
  164.             ];
  165.         }
  166.         $strWhereStatement $this->SQLQueryBuilder->getWhereQuery($arrSQLQuery);
  167.         if (Toolkit::isEmpty($strOrderBy)) {
  168.             $this->CatalogDcExtractor->initialize($this->arrField['dbTable']);
  169.             $this->CatalogDcExtractor->extract();
  170.             if ($this->CatalogDcExtractor->hasOrderByStatement()) {
  171.                 $strOrderBy ' ORDER BY ' $this->CatalogDcExtractor->getOrderByStatement();
  172.             }
  173.         }
  174.         $strQuery sprintf('SELECT * FROM %s%s%s'$this->arrField['dbTable'], $strWhereStatement$strOrderBy);
  175.         if (isset($GLOBALS['TL_HOOKS']['catalogManagerModifyOptionsGetter']) && is_array($GLOBALS['TL_HOOKS']['catalogManagerModifyOptionsGetter'])) {
  176.             foreach ($GLOBALS['TL_HOOKS']['catalogManagerModifyOptionsGetter'] as $callback) {
  177.                 $this->import($callback[0]);
  178.                 $this->{$callback[0]}->{$callback[1]}($strQuery$arrSQLQuery$this->arrField$this->strModuleID);
  179.             }
  180.         }
  181.         $objDbOptions $this->SQLQueryHelper->SQLQueryBuilder->Database->prepare($strQuery)->execute($this->SQLQueryBuilder->getValues());
  182.         return $objDbOptions;
  183.     }
  184.     protected function getActiveTable()
  185.     {
  186.         $this->strActiveTable \Input::get('table') ? \Input::get('table') : \Input::get('ctlg_table');
  187.         if (Toolkit::isEmpty($this->strActiveTable) && \Input::get('do')) {
  188.             $arrTables Toolkit::getBackendModuleTablesByDoAttribute(\Input::get('do'));
  189.             if (is_array($arrTables) && isset($arrTables[0])) $this->strActiveTable $arrTables[0];
  190.         }
  191.     }
  192.     protected function getDbOptions()
  193.     {
  194.         $arrOptions = [];
  195.         $objDbOptions $this->getTableEntities();
  196.         if ($objDbOptions === null) return $arrOptions;
  197.         if (!$objDbOptions->numRows) return $arrOptions;
  198.         while ($objDbOptions->next()) {
  199.             $this->setValueToOption($arrOptions$objDbOptions->{$this->arrField['dbTableKey']}, $objDbOptions->{$this->arrField['dbTableValue']}, $this->arrField['dbTable']);
  200.         }
  201.         $arrOrderBy \StringUtil::deserialize($this->arrField['dbOrderBy'], true);
  202.         if (empty($arrOrderBy) && count($arrOptions) < 50) {
  203.             asort($arrOptions);
  204.         }
  205.         if (isset($GLOBALS['TL_HOOKS']['catalogManagerModifyOptions']) && is_array($GLOBALS['TL_HOOKS']['catalogManagerModifyOptions'])) {
  206.             foreach ($GLOBALS['TL_HOOKS']['catalogManagerModifyOptions'] as $arrCallback) {
  207.                 if (is_array($arrCallback)) {
  208.                     $this->import($arrCallback[0]);
  209.                     $this->{$arrCallback[0]}->{$arrCallback[1]}($arrOptions$this->arrField$this->arrCatalog$this->arrCatalogFields);
  210.                 }
  211.             }
  212.         }
  213.         return $arrOptions;
  214.     }
  215.     protected function getActiveDbOptions()
  216.     {
  217.         $arrOptions = [];
  218.         $objEntities $this->getTableEntities();
  219.         $strDbColumn $this->arrField['dbColumn'];
  220.         if ($objEntities === null) return $arrOptions;
  221.         if (!$objEntities->numRows) return $arrOptions;
  222.         $this->arrCatalog $this->SQLQueryHelper->getCatalogByTablename($this->arrField['dbTable']);
  223.         $this->arrCatalogFields $this->SQLQueryHelper->getCatalogFieldsByCatalogTablename($this->arrField['dbTable']);
  224.         while ($objEntities->next()) {
  225.             $strOriginValue $objEntities->{$strDbColumn};
  226.             $varValue $this->parseCatalogValues($strOriginValue$strDbColumn, []);
  227.             if (is_array($varValue)) {
  228.                 $arrLabels array_values($varValue);
  229.                 $arrOriginValues array_keys($varValue);
  230.                 if (!empty($arrLabels) && is_array($arrLabels)) {
  231.                     foreach ($arrLabels as $intPosition => $strLabel) {
  232.                         $this->setValueToOption($arrOptions$arrOriginValues[$intPosition], $strLabel$this->arrField['dbTable']);
  233.                     }
  234.                 }
  235.             } else {
  236.                 $this->setValueToOption($arrOptions$strOriginValue$varValue$this->arrField['dbTable']);
  237.             }
  238.         }
  239.         $arrOrderBy StringUtil::deserialize($this->arrField['dbOrderBy'], true);
  240.         if (empty($arrOrderBy) && count($arrOptions) < 50) {
  241.             asort($arrOptions);
  242.         }
  243.         if (isset($GLOBALS['TL_HOOKS']['catalogManagerModifyOptions']) && is_array($GLOBALS['TL_HOOKS']['catalogManagerModifyOptions'])) {
  244.             foreach ($GLOBALS['TL_HOOKS']['catalogManagerModifyOptions'] as $arrCallback) {
  245.                 if (is_array($arrCallback)) {
  246.                     $this->import($arrCallback[0]);
  247.                     $this->{$arrCallback[0]}->{$arrCallback[1]}($arrOptions$this->arrField$this->arrCatalog$this->arrCatalogFields);
  248.                 }
  249.             }
  250.         }
  251.         return $arrOptions;
  252.     }
  253.     protected function getParseQueryValue($strValue ''$strOperator '', &$blnValidValue true)
  254.     {
  255.         if (!empty($strValue) && is_string($strValue)) {
  256.             $strInsertTagValue \Controller::replaceInsertTags($strValue);
  257.             if (!Toolkit::isEmpty($strInsertTagValue)) {
  258.                 $strValue $strInsertTagValue;
  259.             }
  260.         }
  261.         if (!empty($strValue) && is_string($strValue) && strpos($strValue'{{') !== false) {
  262.             $strActiveValue '';
  263.             $arrTags preg_split('/{{(([^{}]*|(?R))*)}}/'$strValue, -1PREG_SPLIT_DELIM_CAPTURE);
  264.             $strInsertTag implode(''$arrTags);
  265.             $strParameter explode('::'$strInsertTag);
  266.             $strFieldname $strParameter[0];
  267.             if ($strFieldname !== '' && $strFieldname !== null) {
  268.                 $strActiveValue $this->arrActiveEntity[$strFieldname] ?? '';
  269.                 if (TL_MODE == 'FE') {
  270.                     $strActiveValue $this->CatalogInput->getActiveValue($strFieldname);
  271.                 }
  272.                 if (TL_MODE == 'FE' && (Toolkit::isEmpty(\Input::post('FORM_SUBMIT')) && \Input::get('act' $this->strModuleID))) {
  273.                     $strActiveValue $this->arrActiveEntity[$strFieldname] ?: '';
  274.                 }
  275.                 if (isset($strParameter[1]) && $strParameter[1] == 'tree') {
  276.                     $objDatabase \Database::getInstance();
  277.                     $objField $objDatabase->prepare('SELECT * FROM tl_catalog_fields WHERE `fieldname` = ?')->limit(1)->execute($strFieldname); //@todo don`t work with multiple fieldnames
  278.                     if ($objField->numRows) {
  279.                         if ($objField->optionsType) {
  280.                             $objEntity $objDatabase->prepare('SELECT * FROM ' $objField->dbTable ' WHERE `' $objField->dbTableKey '` = ?')
  281.                                 ->limit(1)
  282.                                 ->execute($strActiveValue);
  283.                             if ($objEntity->numRows) {
  284.                                 $strActiveValue $objEntity->id ?: $strActiveValue;
  285.                             }
  286.                         }
  287.                     }
  288.                 }
  289.             }
  290.             $blnValidValue $this->isValidValue($strActiveValue);
  291.             $strValue $strActiveValue;
  292.         }
  293.         if (in_array($strOperator, ['contain''notContain']) && is_string($strValue)) {
  294.             $strValue explode(','$strValue);
  295.         }
  296.         return Toolkit::prepareValueForQuery($strValue);
  297.     }
  298.     protected function getKeyValueOptions()
  299.     {
  300.         $arrOptions = [];
  301.         if ($this->arrField['options']) {
  302.             $arrFieldOptions \StringUtil::deserialize($this->arrField['options']);
  303.             if (!empty($arrFieldOptions) && is_array($arrFieldOptions)) {
  304.                 foreach ($arrFieldOptions as $arrOption) {
  305.                     $this->setValueToOption($arrOptions$arrOption['key'], $arrOption['value']);
  306.                 }
  307.             }
  308.         }
  309.         return $arrOptions;
  310.     }
  311.     protected function setForeignKey()
  312.     {
  313.         $strLabelColumn $this->arrField['dbTableValue'] ?: $this->arrField['dbTableKey'];
  314.         if (!$this->arrField['dbTable'] || !$strLabelColumn) {
  315.             return '';
  316.         }
  317.         return $this->arrField['dbTable'] . '.' $strLabelColumn;
  318.     }
  319.     protected function getActiveEntityValues()
  320.     {
  321.         switch (TL_MODE) {
  322.             case 'BE':
  323.                 $strID \Input::get('id');
  324.                 if (Toolkit::isEmpty($strID) || Toolkit::isEmpty($this->strActiveTable)) {
  325.                     return null;
  326.                 }
  327.                 if (!$this->SQLQueryHelper->SQLQueryBuilder->Database->tableExists($this->strActiveTable)) {
  328.                     return null;
  329.                 }
  330.                 $arrQuery = [
  331.                     'table' => $this->strActiveTable,
  332.                     'pagination' => [
  333.                         'limit' => 1
  334.                     ],
  335.                     'where' => [
  336.                         [
  337.                             'field' => 'id',
  338.                             'value' => $strID,
  339.                             'operator' => 'equal'
  340.                         ]
  341.                     ],
  342.                     'joins' => []
  343.                 ];
  344.                 $strLanguageColumn '';
  345.                 $strDefaultLanguage '';
  346.                 $objCatalog $this->SQLQueryHelper->SQLQueryBuilder->Database->prepare('SELECT * FROM tl_catalog WHERE tablename = ? LIMIT 1')->execute($this->strActiveTable);
  347.                 if ($objCatalog->numRows) {
  348.                     if ($objCatalog->pTable && $this->SQLQueryHelper->SQLQueryBuilder->Database->fieldExists('pid'$this->strActiveTable)) {
  349.                         $arrQuery['joins'][] = [
  350.                             'field' => 'pid',
  351.                             'onField' => 'id',
  352.                             'multiple' => false,
  353.                             'table' => $this->strActiveTable,
  354.                             'onTable' => $objCatalog->pTable
  355.                         ];
  356.                     }
  357.                     if ($this->hasLanguageNavigationBar($objCatalog)) {
  358.                         $strDefaultLanguage \Input::get('ctlg_language') ?: $objCatalog->fallbackLanguage;
  359.                         $strLanguageColumn $objCatalog->languageEntityColumn;
  360.                     }
  361.                 }
  362.                 $this->arrActiveEntity $this->SQLQueryBuilder->execute($arrQuery)->row();
  363.                 if ($strLanguageColumn && $strDefaultLanguage) {
  364.                     $this->arrActiveEntity[$strLanguageColumn] = $strDefaultLanguage;
  365.                 }
  366.                 return null;
  367.                 break;
  368.             case 'FE':
  369.                 if (!$this->arrField['pid']) {
  370.                     return null;
  371.                 }
  372.                 $objCatalog $this->SQLQueryHelper->SQLQueryBuilder->Database->prepare('SELECT * FROM tl_catalog WHERE id = ?')->limit(1)->execute($this->arrField['pid']);
  373.                 if (!$objCatalog->tablename || !$this->SQLQueryHelper->SQLQueryBuilder->Database->tableExists($objCatalog->tablename)) {
  374.                     return null;
  375.                 }
  376.                 $strID $this->strModuleID \Input::get('id' $this->strModuleID) : \Input::get('id');
  377.                 $strAct $this->strModuleID \Input::get('act' $this->strModuleID) : \Input::get('act');
  378.                 if (!$strID && !$strAct) {
  379.                     return null;
  380.                 }
  381.                 $arrQuery = [
  382.                     'table' => $objCatalog->tablename,
  383.                     'pagination' => [
  384.                         'limit' => 1
  385.                     ],
  386.                     'where' => [
  387.                         [
  388.                             'field' => 'id',
  389.                             'value' => $strID,
  390.                             'operator' => 'equal'
  391.                         ]
  392.                     ],
  393.                     'joins' => []
  394.                 ];
  395.                 if ($objCatalog->pTable && $this->SQLQueryHelper->SQLQueryBuilder->Database->fieldExists('pid'$objCatalog->tablename)) {
  396.                     $arrQuery['joins'][] = [
  397.                         'field' => 'pid',
  398.                         'onField' => 'id',
  399.                         'multiple' => false,
  400.                         'onTable' => $objCatalog->pTable,
  401.                         'table' => $objCatalog->tablename
  402.                     ];
  403.                 }
  404.                 $this->arrActiveEntity $this->SQLQueryBuilder->execute($arrQuery)->row();
  405.                 if ($this->hasLanguageNavigationBar($objCatalog)) {
  406.                     $this->arrActiveEntity[$objCatalog->languageEntityColumn] = $GLOBALS['TL_LANGUAGE'] ?: $objCatalog->fallbackLanguage;
  407.                 }
  408.                 break;
  409.         }
  410.         if (!is_array($this->arrActiveEntity)) {
  411.             $this->arrActiveEntity = [];
  412.         }
  413.     }
  414.     protected function getOrderBy()
  415.     {
  416.         if (isset($this->arrField['dbOrderBy'])) {
  417.             $arrOrderBy \StringUtil::deserialize($this->arrField['dbOrderBy']);
  418.             if (is_array($arrOrderBy) && !empty($arrOrderBy)) {
  419.                 $this->arrField['_orderBy'] = $this->OrderByHelper->getOrderByQuery($arrOrderBy$this->arrField['dbTable']);
  420.             }
  421.         }
  422.         if (isset($this->arrField['_orderBy']) && !Toolkit::isEmpty($this->arrField['_orderBy'])) {
  423.             return ' ' $this->arrField['_orderBy'];
  424.         }
  425.         return '';
  426.     }
  427.     protected function isValidValue($strValue)
  428.     {
  429.         if (!Toolkit::isEmpty($strValue)) return true;
  430.         switch (TL_MODE) {
  431.             case 'BE':
  432.                 $strID \Input::get('id');
  433.                 if (Toolkit::isEmpty($strID) || Toolkit::isEmpty($this->strActiveTable)) return false;
  434.                 break;
  435.             case 'FE':
  436.                 $strID $this->strModuleID \Input::get('id' $this->strModuleID) : \Input::get('id');
  437.                 if (\Input::get('act' $this->strModuleID)) return true;
  438.                 if (!$strID) return false;
  439.                 break;
  440.         }
  441.         return true;
  442.     }
  443.     protected function hasLanguageNavigationBar($objCatalog)
  444.     {
  445.         return $objCatalog->enableLanguageBar && !in_array($objCatalog->mode, ['5''6']) && $objCatalog->languageEntitySource == 'currentTable';
  446.     }
  447. }