/** * Manipulates the SQL query * * @param SQLQuery &$query Query to manipulate * * @return void * * @author Sebastian Diel <*****@*****.**> * @since 04.05.2012 */ public function augmentSQL(SQLQuery &$query) { if (!$query->isJoinedTo($this->getLanguageClassName()) && !$query->getDelete()) { $silvercartDefaultLocale = SilvercartConfig::Locale(); $query->addLeftJoin($this->getLanguageClassName(), sprintf("(\"%s\".\"ID\" = \"%s\".\"%s\")", $this->getBaseClassName(), $this->getLanguageClassName(), $this->getRelationFieldName())); $addToWhere = ''; if ($this->getBaseLanguageClassName() != $this->getLanguageClassName()) { $query->addLeftJoin($this->getBaseLanguageClassName(), sprintf("(\"%s\".\"ID\" = \"%s\".\"ID\")", $this->getLanguageClassName(), $this->getBaseLanguageClassName())); $addToWhere = sprintf("AND \"%s\".\"ID\" = \"%s\".\"ID\"", $this->getBaseLanguageClassName(), $this->getLanguageClassName()); } if (SilvercartConfig::useDefaultLanguageAsFallback() && Translatable::get_current_locale() != $silvercartDefaultLocale && !empty($silvercartDefaultLocale)) { $query->addWhere(sprintf("\"%s\".\"Locale\" = IFNULL((%s), (%s)) %s", $this->getBaseLanguageClassName(), $this->getLocaleDependantSelect(Translatable::get_current_locale()), $this->getLocaleDependantSelect($silvercartDefaultLocale), $addToWhere)); } elseif (!empty($silvercartDefaultLocale)) { $query->addWhere(sprintf("\"%s\".\"Locale\" = '%s' %s", $this->getBaseLanguageClassName(), Translatable::get_current_locale(), $addToWhere)); } } }
/** * Traverse the relationship fields, and add the table * mappings to the query object state. This has to be called * in any overloaded {@link SearchFilter->apply()} methods manually. * * @param String|array $relation The array/dot-syntax relation to follow * @return The model class of the related item */ public function applyRelation($relation) { // NO-OP if (!$relation) { return $this->dataClass; } if (is_string($relation)) { $relation = explode(".", $relation); } $modelClass = $this->dataClass; foreach ($relation as $rel) { $model = singleton($modelClass); if ($component = $model->has_one($rel)) { if (!$this->query->isJoinedTo($component)) { $foreignKey = $rel; $realModelClass = ClassInfo::table_for_object_field($modelClass, "{$foreignKey}ID"); $this->query->addLeftJoin($component, "\"{$component}\".\"ID\" = \"{$realModelClass}\".\"{$foreignKey}ID\""); /** * add join clause to the component's ancestry classes so that the search filter could search on * its ancestor fields. */ $ancestry = ClassInfo::ancestry($component, true); if (!empty($ancestry)) { $ancestry = array_reverse($ancestry); foreach ($ancestry as $ancestor) { if ($ancestor != $component) { $this->query->addInnerJoin($ancestor, "\"{$component}\".\"ID\" = \"{$ancestor}\".\"ID\""); } } } } $modelClass = $component; } elseif ($component = $model->has_many($rel)) { if (!$this->query->isJoinedTo($component)) { $ancestry = $model->getClassAncestry(); $foreignKey = $model->getRemoteJoinField($rel); $this->query->addLeftJoin($component, "\"{$component}\".\"{$foreignKey}\" = \"{$ancestry[0]}\".\"ID\""); /** * add join clause to the component's ancestry classes so that the search filter could search on * its ancestor fields. */ $ancestry = ClassInfo::ancestry($component, true); if (!empty($ancestry)) { $ancestry = array_reverse($ancestry); foreach ($ancestry as $ancestor) { if ($ancestor != $component) { $this->query->addInnerJoin($ancestor, "\"{$component}\".\"ID\" = \"{$ancestor}\".\"ID\""); } } } } $modelClass = $component; } elseif ($component = $model->many_many($rel)) { list($parentClass, $componentClass, $parentField, $componentField, $relationTable) = $component; $parentBaseClass = ClassInfo::baseDataClass($parentClass); $componentBaseClass = ClassInfo::baseDataClass($componentClass); $this->query->addInnerJoin($relationTable, "\"{$relationTable}\".\"{$parentField}\" = \"{$parentBaseClass}\".\"ID\""); $this->query->addLeftJoin($componentBaseClass, "\"{$relationTable}\".\"{$componentField}\" = \"{$componentBaseClass}\".\"ID\""); if (ClassInfo::hasTable($componentClass)) { $this->query->addLeftJoin($componentClass, "\"{$relationTable}\".\"{$componentField}\" = \"{$componentClass}\".\"ID\""); } $modelClass = $componentClass; } } return $modelClass; }
/** * Traverse the relationship fields, and add the table * mappings to the query object state. * * @todo try to make this implicitly triggered so it doesn't have to be manually called in child filters * @param SQLQuery $query * @return SQLQuery */ function applyRelation($query) { if (is_array($this->relation)) { foreach ($this->relation as $rel) { $model = singleton($this->model); if ($component = $model->has_one($rel)) { if (!$query->isJoinedTo($component)) { $foreignKey = $model->getReverseAssociation($component); $query->leftJoin($component, "`{$component}`.`ID` = `{$this->model}`.`{$foreignKey}ID`"); } $this->model = $component; } elseif ($component = $model->has_many($rel)) { if (!$query->isJoinedTo($component)) { $ancestry = $model->getClassAncestry(); $foreignKey = $model->getComponentJoinField($rel); $query->leftJoin($component, "`{$component}`.`{$foreignKey}` = `{$ancestry[0]}`.`ID`"); } $this->model = $component; } elseif ($component = $model->many_many($rel)) { list($parentClass, $componentClass, $parentField, $componentField, $relationTable) = $component; $parentBaseClass = ClassInfo::baseDataClass($parentClass); $componentBaseClass = ClassInfo::baseDataClass($componentClass); $query->innerJoin($relationTable, "`{$relationTable}`.`{$parentField}` = `{$parentBaseClass}`.`ID`"); $query->leftJoin($componentClass, "`{$relationTable}`.`{$componentField}` = `{$componentClass}`.`ID`"); $this->model = $componentClass; // Experimental support for user-defined relationships via a "(relName)Query" method // This will likely be dropped in 2.4 for a system that makes use of Lazy Data Lists. } elseif ($model->hasMethod($rel . 'Query')) { // Get the query representing the join - it should have "$ID" in the filter $newQuery = $model->{"{$rel}Query"}(); if ($newQuery) { // Get the table to join to $newModel = str_replace('`', '', array_shift($newQuery->from)); // Get the filter to use on the join $ancestry = $model->getClassAncestry(); $newFilter = "(" . str_replace('$ID', "`{$ancestry[0]}`.`ID`", implode(") AND (", $newQuery->where)) . ")"; $query->leftJoin($newModel, $newFilter); $this->model = $newModel; } else { $this->name = "NULL"; return; } } } } return $query; }
/** * Traverse the relationship fields, and add the table * mappings to the query object state. This has to be called * in any overloaded {@link SearchFilter->apply()} methods manually. * * @todo try to make this implicitly triggered so it doesn't have to be manually called in child filters * @param SQLQuery $query * @return SQLQuery */ function applyRelation($query) { if (is_array($this->relation)) { foreach ($this->relation as $rel) { $model = singleton($this->model); if ($component = $model->has_one($rel)) { if (!$query->isJoinedTo($component)) { $foreignKey = $model->getReverseAssociation($component); $query->leftJoin($component, "\"{$component}\".\"ID\" = \"{$this->model}\".\"{$foreignKey}ID\""); /** * add join clause to the component's ancestry classes so that the search filter could search on its * ancester fields. */ $ancestry = ClassInfo::ancestry($component, true); if (!empty($ancestry)) { $ancestry = array_reverse($ancestry); foreach ($ancestry as $ancestor) { if ($ancestor != $component) { $query->innerJoin($ancestor, "\"{$component}\".\"ID\" = \"{$ancestor}\".\"ID\""); $component = $ancestor; } } } } $this->model = $component; } elseif ($component = $model->has_many($rel)) { if (!$query->isJoinedTo($component)) { $ancestry = $model->getClassAncestry(); $foreignKey = $model->getRemoteJoinField($rel); $query->leftJoin($component, "\"{$component}\".\"{$foreignKey}\" = \"{$ancestry[0]}\".\"ID\""); /** * add join clause to the component's ancestry classes so that the search filter could search on its * ancestor fields. */ $ancestry = ClassInfo::ancestry($component, true); if (!empty($ancestry)) { $ancestry = array_reverse($ancestry); foreach ($ancestry as $ancestor) { if ($ancestor != $component) { $query->innerJoin($ancestor, "\"{$component}\".\"ID\" = \"{$ancestor}\".\"ID\""); $component = $ancestor; } } } } $this->model = $component; } elseif ($component = $model->many_many($rel)) { list($parentClass, $componentClass, $parentField, $componentField, $relationTable) = $component; $parentBaseClass = ClassInfo::baseDataClass($parentClass); $componentBaseClass = ClassInfo::baseDataClass($componentClass); $query->innerJoin($relationTable, "\"{$relationTable}\".\"{$parentField}\" = \"{$parentBaseClass}\".\"ID\""); $query->leftJoin($componentBaseClass, "\"{$relationTable}\".\"{$componentField}\" = \"{$componentBaseClass}\".\"ID\""); if (ClassInfo::hasTable($componentClass)) { $query->leftJoin($componentClass, "\"{$relationTable}\".\"{$componentField}\" = \"{$componentClass}\".\"ID\""); } $this->model = $componentClass; // Experimental support for user-defined relationships via a "(relName)Query" method // This will likely be dropped in 2.4 for a system that makes use of Lazy Data Lists. } elseif ($model->hasMethod($rel . 'Query')) { // Get the query representing the join - it should have "$ID" in the filter $newQuery = $model->{"{$rel}Query"}(); if ($newQuery) { // Get the table to join to //DATABASE ABSTRACTION: I don't think we need this line anymore: $newModel = str_replace('`', '', array_shift($newQuery->from)); // Get the filter to use on the join $ancestry = $model->getClassAncestry(); $newFilter = "(" . str_replace('$ID', "\"{$ancestry[0]}\".\"ID\"", implode(") AND (", $newQuery->where)) . ")"; $query->leftJoin($newModel, $newFilter); $this->model = $newModel; } else { $this->name = "NULL"; return; } } } } return $query; }