/** * Build a query based on the given options * * @param array $arrOptions The options array * * @return string The query string */ public static function find($arrOptions) { $objBase = new \DcaExtractor($arrOptions['table']); if (!$objBase->hasRelations()) { $strQuery = "SELECT * FROM " . $arrOptions['table']; } else { $arrJoins = array(); $arrFields = array($arrOptions['table'] . ".*"); $intCount = 0; foreach ($objBase->getRelations() as $strKey => $arrConfig) { // Automatically join the single-relation records if ($arrConfig['load'] == 'eager' || $arrOptions['eager']) { if ($arrConfig['type'] == 'hasOne' || $arrConfig['type'] == 'belongsTo') { ++$intCount; $objRelated = new \DcaExtractor($arrConfig['table']); foreach (array_keys($objRelated->getFields()) as $strField) { $arrFields[] = 'j' . $intCount . '.' . $strField . ' AS ' . $strKey . '__' . $strField; } $arrJoins[] = " LEFT JOIN " . $arrConfig['table'] . " j{$intCount} ON " . $arrOptions['table'] . "." . $strKey . "=j{$intCount}.id"; } } } // Generate the query $strQuery = "SELECT " . implode(', ', $arrFields) . " FROM " . $arrOptions['table'] . implode("", $arrJoins); } // Where condition if ($arrOptions['column'] !== null) { $strQuery .= " WHERE " . (is_array($arrOptions['column']) ? implode(" AND ", $arrOptions['column']) : $arrOptions['table'] . '.' . $arrOptions['column'] . "=?"); } // Order by if ($arrOptions['order'] !== null) { $strQuery .= " ORDER BY " . $arrOptions['order']; } return $strQuery; }
/** * Return select statement to load product data including multilingual fields * @param array an array of columns * @return string */ protected static function buildFindQuery(array $arrOptions) { $objBase = new \DcaExtractor($arrOptions['table']); $arrJoins = array(); $arrFields = array($arrOptions['table'] . ".*", "IF(" . $arrOptions['table'] . ".pid>0, parent.type, " . $arrOptions['table'] . ".type) AS type", "'" . str_replace('-', '_', $GLOBALS['TL_LANGUAGE']) . "' AS language"); foreach (Attribute::getMultilingualFields() as $attribute) { $arrFields[] = "IFNULL(translation.{$attribute}, " . $arrOptions['table'] . ".{$attribute}) AS {$attribute}"; } foreach (Attribute::getFetchFallbackFields() as $attribute) { $arrFields[] = "{$arrOptions['table']}.{$attribute} AS {$attribute}_fallback"; } $arrFields[] = "c.sorting"; $arrJoins[] = " LEFT OUTER JOIN " . \Isotope\Model\ProductCategory::getTable() . " c ON {$arrOptions['table']}.id=c.pid"; $arrJoins[] = " LEFT OUTER JOIN " . $arrOptions['table'] . " translation ON " . $arrOptions['table'] . ".id=translation.pid AND translation.language='" . str_replace('-', '_', $GLOBALS['TL_LANGUAGE']) . "'"; $arrJoins[] = " LEFT OUTER JOIN " . $arrOptions['table'] . " parent ON " . $arrOptions['table'] . ".pid=parent.id"; if ($objBase->hasRelations()) { $intCount = 0; foreach ($objBase->getRelations() as $strKey => $arrConfig) { // Automatically join the single-relation records if ($arrConfig['load'] == 'eager' || $arrOptions['eager']) { if ($arrConfig['type'] == 'hasOne' || $arrConfig['type'] == 'belongsTo') { if (is_array($arrOptions['joinAliases']) && ($key = array_search($arrConfig['table'], $arrOptions['joinAliases'])) !== false) { $strJoinAlias = $key; unset($arrOptions['joinAliases'][$key]); } else { ++$intCount; $strJoinAlias = 'j' . $intCount; } $objRelated = new \DcaExtractor($arrConfig['table']); foreach (array_keys($objRelated->getFields()) as $strField) { $arrFields[] = $strJoinAlias . '.' . $strField . ' AS ' . $strKey . '__' . $strField; } $arrJoins[] = " LEFT JOIN " . $arrConfig['table'] . " {$strJoinAlias} ON " . $arrOptions['table'] . "." . $strKey . "={$strJoinAlias}.id"; } } } } // Generate the query $strQuery = "SELECT " . implode(', ', $arrFields) . " FROM " . $arrOptions['table'] . implode("", $arrJoins); // Where condition if (!is_array($arrOptions['column'])) { $arrOptions['column'] = array($arrOptions['table'] . '.' . $arrOptions['column'] . '=?'); } // The model must never find a language record $strQuery .= " WHERE {$arrOptions['table']}.language='' AND " . implode(" AND ", $arrOptions['column']); // Group by if ($arrOptions['group'] !== null) { $strQuery .= " GROUP BY " . $arrOptions['group']; } // Order by if ($arrOptions['order'] !== null) { $strQuery .= " ORDER BY " . $arrOptions['order']; } return $strQuery; }
/** * Return a model or collection based on the database result type * * @param array $arrOptions * * @return \Model|\Model\Collection|null */ protected static function find(array $arrOptions) { if (static::$strTable == '') { return null; } // if find() method is called in a specific model type, results must be of that type if (($strType = array_search(get_called_class(), static::getModelTypes())) !== false) { // Convert to array if necessary $arrOptions['value'] = (array) $arrOptions['value']; if (!is_array($arrOptions['column'])) { $arrOptions['column'] = array(static::$strTable . '.' . $arrOptions['column'] . '=?'); } $objRelations = new \DcaExtractor(static::$strTable); $arrRelations = $objRelations->getRelations(); $arrFields = $objRelations->getFields(); // @deprecated use string instead of array for HAVING (introduced in Contao 3.3) if (!empty($arrOptions['having']) && is_array($arrOptions['having'])) { $arrOptions['having'] = implode(' AND ', $arrOptions['having']); } if (isset($arrRelations['type'])) { $arrOptions['having'] = (empty($arrOptions['having']) ? '' : ' AND ') . 'type IN (SELECT ' . $arrRelations['type']['field'] . ' FROM ' . $arrRelations['type']['table'] . ' WHERE class=?)'; $arrOptions['value'][] = $strType; } elseif (isset($arrFields['type'])) { $arrOptions['having'] = (empty($arrOptions['having']) ? '' : ' AND ') . 'type=?'; $arrOptions['value'][] = $strType; } } $arrOptions['table'] = static::$strTable; // @deprecated use static::buildFindQuery once we drop BC support for buildQueryString $strQuery = static::buildQueryString($arrOptions); $objStatement = \Database::getInstance()->prepare($strQuery); // Defaults for limit and offset if (!isset($arrOptions['limit'])) { $arrOptions['limit'] = 0; } if (!isset($arrOptions['offset'])) { $arrOptions['offset'] = 0; } // Limit if ($arrOptions['limit'] > 0 || $arrOptions['offset'] > 0) { $objStatement->limit($arrOptions['limit'], $arrOptions['offset']); } $objStatement = static::preFind($objStatement); $objResult = $objStatement->execute($arrOptions['value']); if ($objResult->numRows < 1) { return null; } $objResult = static::postFind($objResult); if ($arrOptions['return'] == 'Model') { // @deprecated use static::createModelFromDbResult once we drop BC support for buildModelType return static::buildModelType($objResult); } else { return static::createCollectionFromDbResult($objResult, static::$strTable); } }
/** * Create the DCA extract cache files */ public function generateDcaExtracts() { $included = array(); $arrExtracts = array(); // Only check the active modules (see #4541) foreach (\ModuleLoader::getActive() as $strModule) { $strDir = 'system/modules/' . $strModule . '/dca'; if (!is_dir(TL_ROOT . '/' . $strDir)) { continue; } foreach (scan(TL_ROOT . '/' . $strDir) as $strFile) { // Ignore non PHP files and files which have been included before if (strncmp($strFile, '.', 1) === 0 || substr($strFile, -4) != '.php' || in_array($strFile, $included)) { continue; } $strTable = substr($strFile, 0, -4); $objExtract = new \DcaExtractor($strTable); if ($objExtract->isDbTable()) { $arrExtracts[$strTable] = $objExtract; } $included[] = $strFile; } } // Create one file per table foreach ($arrExtracts as $strTable => $objExtract) { // Create the file $objFile = new \File('system/cache/sql/' . $strTable . '.php', true); $objFile->write("<?php\n\n"); // Meta $arrMeta = $objExtract->getMeta(); $objFile->append("\$this->arrMeta = array\n("); $objFile->append("\t'engine' => '{$arrMeta['engine']}',"); $objFile->append("\t'charset' => '{$arrMeta['charset']}',"); $objFile->append(');', "\n\n"); // Fields $arrFields = $objExtract->getFields(); $objFile->append("\$this->arrFields = array\n("); foreach ($arrFields as $field => $sql) { $sql = str_replace('"', '\\"', $sql); $objFile->append("\t'{$field}' => \"{$sql}\","); } $objFile->append(');', "\n\n"); // Order fields $arrFields = $objExtract->getOrderFields(); $objFile->append("\$this->arrOrderFields = array\n("); foreach ($arrFields as $field) { $objFile->append("\t'{$field}',"); } $objFile->append(');', "\n\n"); // Keys $arrKeys = $objExtract->getKeys(); $objFile->append("\$this->arrKeys = array\n("); foreach ($arrKeys as $field => $type) { $objFile->append("\t'{$field}' => '{$type}',"); } $objFile->append(');', "\n\n"); // Relations $arrRelations = $objExtract->getRelations(); $objFile->append("\$this->arrRelations = array\n("); foreach ($arrRelations as $field => $config) { $objFile->append("\t'{$field}' => array\n\t("); foreach ($config as $k => $v) { $objFile->append("\t\t'{$k}' => '{$v}',"); } $objFile->append("\t),"); } $objFile->append(');', "\n\n"); // Set the database table flag $objFile->append("\$this->blnIsDbTable = true;", "\n"); // Close the file (moves it to its final destination) $objFile->close(); } // Add a log entry $this->log('Generated the DCA extracts', __METHOD__, TL_CRON); }