/** * 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'); $modesToAllowVersioning = array('all_versions', 'latest_versions', 'archive', 'version'); if (!empty($dataObject->Version) && (!empty($versionedMode) && in_array($versionedMode, $modesToAllowVersioning))) { // This will ensure that augmentSQL will select only the same version as the owner, // regardless of how this object was initially selected $versionColumn = $this->owner->getSchema()->sqlColumnForField($this->owner, 'Version'); $dataQuery->where([$versionColumn => $dataObject->Version]); $dataQuery->setQueryParam('Versioned.mode', 'all_versions'); } }
/** * Loads all the stub fields that an initial lazy load didn't load fully. * * @param string $class Class to load the values from. Others are joined as required. * Not specifying a tableClass will load all lazy fields from all tables. * @return bool Flag if lazy loading succeeded */ protected function loadLazyFields($class = null) { if (!$this->isInDB() || !is_numeric($this->ID)) { return false; } if (!$class) { $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 false; } $dataQuery = new DataQuery($class); // Reset query parameter context to that of this DataObject if ($params = $this->getSourceQueryParams()) { foreach ($params as $key => $value) { $dataQuery->setQueryParam($key, $value); } } // Limit query to the current record, unless it has the Versioned extension, // in which case it requires special handling through augmentLoadLazyFields() $schema = static::getSchema(); $baseIDColumn = $schema->sqlColumnForField($this, 'ID'); $dataQuery->where([$baseIDColumn => $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 = $schema->databaseFields($class, false); 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']); } } } return true; }
/** * Invoked after getFinalisedQuery() * * @param DataQuery $dataQuery * @param array $queriedColumns * @param SQLSelect $sqlQuery */ public function afterGetFinalisedQuery(DataQuery $dataQuery, $queriedColumns = [], SQLSelect $sqlQuery) { // Inject final replacement after manipulation has been performed on the base dataquery $joinTableSQL = $dataQuery->getQueryParam('Foreign.JoinTableSQL'); if ($joinTableSQL) { $sqlQuery->replaceText('SELECT $$_SUBQUERY_$$', $joinTableSQL); $dataQuery->setQueryParam('Foreign.JoinTableSQL', null); } }