/**
  * Applies an exact match (equals) on a field value against multiple
  * possible values.
  *
  * @return DataQuery
  */
 protected function applyMany(DataQuery $query)
 {
     $this->model = $query->applyRelation($this->relation);
     $modifiers = $this->getModifiers();
     $values = array();
     foreach ($this->getValue() as $value) {
         $values[] = Convert::raw2sql($value);
     }
     $CategoryModel = $this->model;
     $this->setModel("DataObjectAsPage");
     $match = array();
     foreach ($values as &$v) {
         $match[] = sprintf("%s IN (\n\t\t\t\t   SELECT " . $query->dataClass() . "ID\n\t\t\t\t   FROM `" . $query->dataClass() . "_" . $this->relation[0] . "`\n\t\t\t\t   WHERE " . $CategoryModel . "ID = '%s'\n\t\t\t\t   GROUP BY " . $query->dataClass() . "ID\n\t\t\t\t)", $this->getDbName(), $v);
     }
     $where = implode(' AND ', $match);
     return $query->where($where);
 }
 /**
  * @param SQLQuery $query
  * @param DataQuery $dataQuery
  */
 function augmentSQL(SQLQuery &$query, DataQuery &$dataQuery = null)
 {
     $baseTable = ClassInfo::baseDataClass($dataQuery->dataClass());
     if (class_exists('Subsite')) {
         $currentSubsiteID = Subsite::currentSubsiteID();
         $query->addWhere("\"{$baseTable}\".\"SubsiteID\" = '{$currentSubsiteID}'");
     }
 }
 /**
  * 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);
     }
 }
Example #4
0
 /**
  * Augment the the SQLQuery that is created by the DataQuery
  * @todo Should this all go into VersionedDataQuery?
  */
 function augmentSQL(SQLQuery &$query, DataQuery &$dataQuery)
 {
     $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->from as $table => $dummy) {
                 $query->renameTable($table, $table . '_versions');
                 $query->replaceText("\"{$table}\".\"ID\"", "\"{$table}\".\"RecordID\"");
                 // Add all <basetable>_versions columns
                 foreach (self::$db_for_versions_table as $name => $type) {
                     $query->select[] = sprintf('"%s_versions"."%s"', $baseTable, $name);
                 }
                 $query->select[] = sprintf('"%s_versions"."%s" AS "ID"', $baseTable, 'RecordID');
                 if ($table != $baseTable) {
                     $query->from[$table] .= " AND \"{$table}_versions\".\"Version\" = \"{$baseTable}_versions\".\"Version\"";
                 }
             }
             // Link to the version archived on that date
             $archiveTable = $this->requireArchiveTempTable($baseTable, $date);
             $query->from[$archiveTable] = "INNER JOIN \"{$archiveTable}\"\n\t\t\t\tON \"{$archiveTable}\".\"ID\" = \"{$baseTable}_versions\".\"RecordID\" \n\t\t\t\tAND \"{$archiveTable}\".\"Version\" = \"{$baseTable}_versions\".\"Version\"";
             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->from 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;
             // Return all version instances
         // Return all version instances
         case 'all_versions':
         case 'latest_versions':
             foreach ($query->from 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->selectMore(sprintf('"%s_versions"."%s"', $baseTable, $name));
             }
             $query->selectMore(sprintf('"%s_versions"."%s" AS "ID"', $baseTable, 'RecordID'));
             // 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') {
                 $archiveTable = self::requireArchiveTempTable($baseTable);
                 $query->innerJoin($archiveTable, "\"{$archiveTable}\".\"ID\" = \"{$baseTable}_versions\".\"RecordID\" AND \"{$archiveTable}\".\"Version\" = \"{$baseTable}_versions\".\"Version\"");
             }
             break;
         default:
             throw new InvalidArgumentException("Bad value for query parameter Versioned.mode: " . $dataQuery->getQueryParam('Versioned.mode'));
     }
 }
Example #5
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'));
     }
 }