/**
  * @return \SQLQuery
  */
 public function getQuery()
 {
     if (!$this->queryCache) {
         if ($this->dataClass) {
             $dataQuery = new \DataQuery($this->dataClass);
             if ($this->stage) {
                 $dataQuery->setQueryParam('Versioned.mode', 'stage');
                 $dataQuery->setQueryParam('Versioned.stage', $this->stage);
             }
             $this->queryCache = $dataQuery->getFinalisedQuery();
         } else {
             $this->queryCache = new \SQLQuery();
         }
         if (is_array($this->queryModifiers)) {
             foreach ($this->queryModifiers as $queryModifier) {
                 if ($queryModifier instanceof QueryModifierInterface) {
                     $queryModifier->modify($this->queryCache, $this->data, $this);
                 } elseif (is_callable($queryModifier)) {
                     $queryModifier($this->queryCache, $this->data, $this);
                 }
             }
         }
     }
     return $this->queryCache;
 }
 /**
  * Amend freshly created DataQuery objects with the "should filter admin?" option, current locale and frontend status
  *
  * @param SQLQuery
  * @param DataQuery
  */
 public function augmentDataQueryCreation(SQLQuery $query, DataQuery $dataQuery)
 {
     $dataQuery->setQueryParam('Fluent.FilterAdmin', Fluent::config()->filter_admin);
     $dataQuery->setQueryParam('Fluent.Locale', Fluent::current_locale());
     $dataQuery->setQueryParam('Fluent.IsFrontend', Fluent::is_frontend());
 }
Exemplo n.º 3
0
 /**
  * Loads all the stub fields that an initial lazy load didn't load fully.
  *
  * @param tableClass Base table to load the values from. Others are joined as required.
  *                   Not specifying a tableClass will load all lazy fields from all tables.
  */
 protected function loadLazyFields($tableClass = null)
 {
     if (!$tableClass) {
         $loaded = array();
         foreach ($this->record as $key => $value) {
             if (strlen($key) > 5 && substr($key, -5) == '_Lazy' && !array_key_exists($value, $loaded)) {
                 $this->loadLazyFields($value);
                 $loaded[$value] = $value;
             }
         }
         return;
     }
     $dataQuery = new DataQuery($tableClass);
     // Reset query parameter context to that of this DataObject
     if ($params = $this->getSourceQueryParams()) {
         foreach ($params as $key => $value) {
             $dataQuery->setQueryParam($key, $value);
         }
     }
     // TableField sets the record ID to "new" on new row data, so don't try doing anything in that case
     if (!is_numeric($this->record['ID'])) {
         return false;
     }
     // Limit query to the current record, unless it has the Versioned extension,
     // in which case it requires special handling through augmentLoadLazyFields()
     if (!$this->hasExtension('Versioned')) {
         $dataQuery->where("\"{$tableClass}\".\"ID\" = {$this->record['ID']}")->limit(1);
     }
     $columns = array();
     // Add SQL for fields, both simple & multi-value
     // TODO: This is copy & pasted from buildSQL(), it could be moved into a method
     $databaseFields = self::database_fields($tableClass);
     if ($databaseFields) {
         foreach ($databaseFields as $k => $v) {
             if (!isset($this->record[$k]) || $this->record[$k] === null) {
                 $columns[] = $k;
             }
         }
     }
     if ($columns) {
         $query = $dataQuery->query();
         $this->extend('augmentLoadLazyFields', $query, $dataQuery, $this);
         $this->extend('augmentSQL', $query, $dataQuery);
         $dataQuery->setQueriedColumns($columns);
         $newData = $dataQuery->execute()->record();
         // Load the data into record
         if ($newData) {
             foreach ($newData as $k => $v) {
                 if (in_array($k, $columns)) {
                     $this->record[$k] = $v;
                     $this->original[$k] = $v;
                     unset($this->record[$k . '_Lazy']);
                 }
             }
             // No data means that the query returned nothing; assign 'null' to all the requested fields
         } else {
             foreach ($columns as $k) {
                 $this->record[$k] = null;
                 $this->original[$k] = null;
                 unset($this->record[$k . '_Lazy']);
             }
         }
     }
 }
 /**
  * Amend freshly created DataQuery objects with the current locale and frontend status
  *
  * @param SQLQuery
  * @param DataQuery
  */
 public function augmentDataQueryCreation(SQLQuery $query, DataQuery $dataQuery)
 {
     $dataQuery->setQueryParam('Fluent.Locale', Fluent::current_locale());
     $dataQuery->setQueryParam('Fluent.IsFrontend', Fluent::is_frontend());
 }
Exemplo n.º 5
0
 /**
  * Amend freshly created DataQuery objects with versioned-specific information 
  */
 function augmentDataQueryCreation(SQLQuery &$query, DataQuery &$dataQuery)
 {
     $parts = explode('.', Versioned::get_reading_mode());
     if ($parts[0] == 'Archive') {
         $dataQuery->setQueryParam('Versioned.mode', 'archive');
         $dataQuery->setQueryParam('Versioned.date', $parts[1]);
     } else {
         if ($parts[0] == 'Stage' && $parts[1] != $this->defaultStage && array_search($parts[1], $this->stages) !== false) {
             $dataQuery->setQueryParam('Versioned.mode', 'stage');
             $dataQuery->setQueryParam('Versioned.stage', $parts[1]);
         }
     }
 }
 /**
  * For lazy loaded fields requiring extra sql manipulation, ie versioning.
  *
  * @param SQLSelect $query
  * @param DataQuery $dataQuery
  * @param DataObject $dataObject
  */
 public function augmentLoadLazyFields(SQLSelect &$query, DataQuery &$dataQuery = null, $dataObject)
 {
     // The VersionedMode local variable ensures that this decorator only applies to
     // queries that have originated from the Versioned object, and have the Versioned
     // metadata set on the query object. This prevents regular queries from
     // accidentally querying the *_versions tables.
     $versionedMode = $dataObject->getSourceQueryParam('Versioned.mode');
     $dataClass = $dataQuery->dataClass();
     $modesToAllowVersioning = array('all_versions', 'latest_versions', 'archive');
     if (!empty($dataObject->Version) && (!empty($versionedMode) && in_array($versionedMode, $modesToAllowVersioning))) {
         $dataQuery->where("\"{$dataClass}\".\"RecordID\" = " . $dataObject->ID);
         $dataQuery->where("\"{$dataClass}\".\"Version\" = " . $dataObject->Version);
         $dataQuery->setQueryParam('Versioned.mode', 'all_versions');
     } else {
         // Same behaviour as in DataObject->loadLazyFields
         $dataQuery->where("\"{$dataClass}\".\"ID\" = {$dataObject->ID}")->limit(1);
     }
 }
 public function augmentDataQueryCreation(SQLSelect $sqlQuery, DataQuery $dataQuery)
 {
     $enabled = self::locale_filter_enabled();
     $dataQuery->setQueryParam(self::QUERY_LOCALE_FILTER_ENABLED, $enabled);
 }
Exemplo n.º 8
0
 /**
  * Augment the the SQLQuery that is created by the DataQuery
  * @todo Should this all go into VersionedDataQuery?
  */
 public function augmentSQL(SQLQuery &$query, DataQuery &$dataQuery = null)
 {
     $baseTable = ClassInfo::baseDataClass($dataQuery->dataClass());
     switch ($dataQuery->getQueryParam('Versioned.mode')) {
         // Noop
         case '':
             break;
             // Reading a specific data from the archive
         // Reading a specific data from the archive
         case 'archive':
             $date = $dataQuery->getQueryParam('Versioned.date');
             foreach ($query->getFrom() as $table => $dummy) {
                 $query->renameTable($table, $table . '_versions');
                 $query->replaceText("\"{$table}_versions\".\"ID\"", "\"{$table}_versions\".\"RecordID\"");
                 $query->replaceText("`{$table}_versions`.`ID`", "`{$table}_versions`.`RecordID`");
                 // Add all <basetable>_versions columns
                 foreach (self::$db_for_versions_table as $name => $type) {
                     $query->selectField(sprintf('"%s_versions"."%s"', $baseTable, $name), $name);
                 }
                 $query->selectField(sprintf('"%s_versions"."%s"', $baseTable, 'RecordID'), "ID");
                 if ($table != $baseTable) {
                     $query->addWhere("\"{$table}_versions\".\"Version\" = \"{$baseTable}_versions\".\"Version\"");
                 }
             }
             // Link to the version archived on that date
             $safeDate = Convert::raw2sql($date);
             $query->addWhere("\"{$baseTable}_versions\".\"Version\" IN \n\t\t\t\t\t(SELECT LatestVersion FROM \n\t\t\t\t\t\t(SELECT \n\t\t\t\t\t\t\t\"{$baseTable}_versions\".\"RecordID\", \n\t\t\t\t\t\t\tMAX(\"{$baseTable}_versions\".\"Version\") AS LatestVersion\n\t\t\t\t\t\t\tFROM \"{$baseTable}_versions\"\n\t\t\t\t\t\t\tWHERE \"{$baseTable}_versions\".\"LastEdited\" <= '{$safeDate}'\n\t\t\t\t\t\t\tGROUP BY \"{$baseTable}_versions\".\"RecordID\"\n\t\t\t\t\t\t) AS \"{$baseTable}_versions_latest\"\n\t\t\t\t\t\tWHERE \"{$baseTable}_versions_latest\".\"RecordID\" = \"{$baseTable}_versions\".\"RecordID\"\n\t\t\t\t\t)");
             break;
             // Reading a specific stage (Stage or Live)
         // Reading a specific stage (Stage or Live)
         case 'stage':
             $stage = $dataQuery->getQueryParam('Versioned.stage');
             if ($stage && $stage != $this->defaultStage) {
                 foreach ($query->getFrom() as $table => $dummy) {
                     // Only rewrite table names that are actually part of the subclass tree
                     // This helps prevent rewriting of other tables that get joined in, in
                     // particular, many_many tables
                     if (class_exists($table) && ($table == $this->owner->class || is_subclass_of($table, $this->owner->class) || is_subclass_of($this->owner->class, $table))) {
                         $query->renameTable($table, $table . '_' . $stage);
                     }
                 }
             }
             break;
             // Reading a specific stage, but only return items that aren't in any other stage
         // Reading a specific stage, but only return items that aren't in any other stage
         case 'stage_unique':
             $stage = $dataQuery->getQueryParam('Versioned.stage');
             // Recurse to do the default stage behavior (must be first, we rely on stage renaming happening before
             // below)
             $dataQuery->setQueryParam('Versioned.mode', 'stage');
             $this->augmentSQL($query, $dataQuery);
             // Now exclude any ID from any other stage. Note that we double rename to avoid the regular stage rename
             // renaming all subquery references to be Versioned.stage
             foreach ($this->stages as $excluding) {
                 if ($excluding == $stage) {
                     continue;
                 }
                 $tempName = 'ExclusionarySource_' . $excluding;
                 $excludingTable = $baseTable . ($excluding && $excluding != $this->defaultStage ? "_{$excluding}" : '');
                 $query->addWhere('"' . $baseTable . '"."ID" NOT IN (SELECT "ID" FROM "' . $tempName . '")');
                 $query->renameTable($tempName, $excludingTable);
             }
             break;
             // Return all version instances
         // Return all version instances
         case 'all_versions':
         case 'latest_versions':
             foreach ($query->getFrom() as $alias => $join) {
                 if ($alias != $baseTable) {
                     $query->setJoinFilter($alias, "\"{$alias}\".\"RecordID\" = \"{$baseTable}_versions\".\"RecordID\"" . " AND \"{$alias}\".\"Version\" = \"{$baseTable}_versions\".\"Version\"");
                 }
                 $query->renameTable($alias, $alias . '_versions');
             }
             // Add all <basetable>_versions columns
             foreach (self::$db_for_versions_table as $name => $type) {
                 $query->selectField(sprintf('"%s_versions"."%s"', $baseTable, $name), $name);
             }
             $query->selectField(sprintf('"%s_versions"."%s"', $baseTable, 'RecordID'), "ID");
             $query->addOrderBy(sprintf('"%s_versions"."%s"', $baseTable, 'Version'));
             // latest_version has one more step
             // Return latest version instances, regardless of whether they are on a particular stage
             // This provides "show all, including deleted" functonality
             if ($dataQuery->getQueryParam('Versioned.mode') == 'latest_versions') {
                 $query->addWhere("\"{$alias}_versions\".\"Version\" IN \n\t\t\t\t\t(SELECT LatestVersion FROM \n\t\t\t\t\t\t(SELECT \n\t\t\t\t\t\t\t\"{$alias}_versions\".\"RecordID\", \n\t\t\t\t\t\t\tMAX(\"{$alias}_versions\".\"Version\") AS LatestVersion\n\t\t\t\t\t\t\tFROM \"{$alias}_versions\"\n\t\t\t\t\t\t\tGROUP BY \"{$alias}_versions\".\"RecordID\"\n\t\t\t\t\t\t) AS \"{$alias}_versions_latest\"\n\t\t\t\t\t\tWHERE \"{$alias}_versions_latest\".\"RecordID\" = \"{$alias}_versions\".\"RecordID\"\n\t\t\t\t\t)");
             }
             break;
         default:
             throw new InvalidArgumentException("Bad value for query parameter Versioned.mode: " . $dataQuery->getQueryParam('Versioned.mode'));
     }
 }