예제 #1
0
 /**
  * Join the given has_many relation to this query.
  *
  * Doesn't work with polymorphic relationships
  *
  * @param string $localClass Name of class that has the has_many to the joined class
  * @param string $localField Name of the has_many relationship to join
  * @param string $foreignClass Class to join
  */
 protected function joinHasManyRelation($localClass, $localField, $foreignClass)
 {
     if (!$foreignClass || $foreignClass === 'DataObject') {
         throw new InvalidArgumentException("Could not find a has_many relationship {$localField} on {$localClass}");
     }
     // Skip if already joined
     if ($this->query->isJoinedTo($foreignClass)) {
         return;
     }
     // Join table with associated has_one
     $model = singleton($localClass);
     $ancestry = $model->getClassAncestry();
     $foreignKey = $model->getRemoteJoinField($localField, 'has_many', $polymorphic);
     if ($polymorphic) {
         $this->query->addLeftJoin($foreignClass, "\"{$foreignClass}\".\"{$foreignKey}ID\" = \"{$ancestry[0]}\".\"ID\" AND " . "\"{$foreignClass}\".\"{$foreignKey}Class\" = \"{$ancestry[0]}\".\"ClassName\"");
     } else {
         $this->query->addLeftJoin($foreignClass, "\"{$foreignClass}\".\"{$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($foreignClass, true);
     $ancestry = array_reverse($ancestry);
     foreach ($ancestry as $ancestor) {
         if ($ancestor != $foreignClass) {
             $this->query->addInnerJoin($ancestor, "\"{$foreignClass}\".\"ID\" = \"{$ancestor}\".\"ID\"");
         }
     }
 }
 /**
  * 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 = $model->getReverseAssociation($component);
                 $this->query->addLeftJoin($component, "\"{$component}\".\"ID\" = \"{$modelClass}\".\"{$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;
 }