예제 #1
0
 /**
  * Add a JOIN clause to a Zend_Db_Select object
  *
  * @param Zend_Db_Select $select The select object
  * @param array $related Collection of related models
  * @param string $rule Used to figure out the relationship metadata from the referencemap
  * @param string $bindingModel Binding model used in HABTM relations
  * @param bool $bidirectional
  * @return void
  */
 protected function _addJoinClause(Zend_Db_Select $select, array $related, $rule = null, $bindingModel = null, $bidirectional = true)
 {
     foreach ($related as $filterModelName => $filterValue) {
         $fieldInfo = explode('.', $filterModelName, 2);
         $filterModelName = Garp_Content_Api::modelAliasToClass($fieldInfo[0]);
         $filterColumn = $fieldInfo[1];
         $filterModel = new $filterModelName();
         /**
          * Determine wether a negation clause (e.g. !=) is requested
          * and normalize the filterColumn.
          */
         $negation = strpos($filterColumn, '<>') !== false;
         $filterColumn = str_replace(' <>', '', $filterColumn);
         if ($filterModelName === get_class($this->_model)) {
             /*  This is a homophile relation and the current condition touches the
                     homophile model.
                     The following condition prevents a 'relatable' list to include the
                     current record, because a record cannot be related to itself.
                 */
             $select->where($this->_getTableName($filterModel) . '.' . $filterColumn . ' != ?', $filterValue);
         }
         try {
             // the other model is a child
             $reference = $filterModel->getReference(get_class($this->_model), $rule);
             $this->_addHasManyClause(array('select' => $select, 'filterModel' => $filterModel, 'reference' => $reference, 'filterColumn' => $filterColumn, 'filterValue' => $filterValue, 'negation' => $negation));
         } catch (Zend_Db_Table_Exception $e) {
             try {
                 // the other model is the parent
                 $reference = $this->_model->getReference(get_class($filterModel), $rule);
                 $this->_addBelongsToClause(array('select' => $select, 'reference' => $reference, 'filterColumn' => $filterColumn, 'filterValue' => $filterValue, 'negation' => $negation));
             } catch (Zend_Db_Table_Exception $e) {
                 try {
                     // the models are equal; a binding model is needed
                     $this->_addHasAndBelongsToManyClause(array('select' => $select, 'filterModel' => $filterModel, 'filterColumn' => $filterColumn, 'filterValue' => $filterValue, 'negation' => $negation, 'bindingModel' => $bindingModel, 'bidirectional' => $bidirectional));
                 } catch (Zend_Db_Table_Exception $e) {
                     throw $e;
                 }
             }
         }
     }
 }
예제 #2
0
 /**
  * Find a related recordset.
  * @param Garp_Model $model The model that spawned this data
  * @param Garp_Db_Row $row The row object
  * @param Garp_Util_Configuration $options Various relation options
  * @return String The name of the method.
  */
 protected function _getRelatedRowset(Garp_Model $model, Garp_Db_Table_Row $row, Garp_Util_Configuration $options)
 {
     /**
      * An optional passed SELECT object will be passed by reference after every query.
      * This results in an error when 'clone' is not used, because correlation names will be
      * used twice (since they were set during the first iteration). Using 'clone' makes sure
      * a brand new SELECT object is used every time that hasn't been soiled by a possible
      * previous query.
      */
     $conditions = is_null($options['conditions']) ? null : clone $options['conditions'];
     $otherModel = $options['modelClass'];
     if (!$otherModel instanceof Zend_Db_Table_Abstract) {
         $otherModel = new $otherModel();
     }
     /**
      * Do not cache related queries. The "outside" query should be the only
      * query that's cached.
      */
     $originalCacheQueriesFlag = $otherModel->getCacheQueries();
     $otherModel->setCacheQueries(false);
     $modelName = get_class($otherModel);
     $relatedRowset = null;
     // many to many
     if (!empty($options['bindingModel'])) {
         $relatedRowset = $row->findManyToManyRowset($otherModel, $options['bindingModel'], $options['rule2'], $options['rule'], $conditions);
     } else {
         /**
          * 'mode' is used to clear ambiguity with homophilic relationships. For example,
          * a Model_Doc can have have child Docs and one parent Doc. The conditionals below can never tell
          * which method to call (findParentRow or findDependentRowset) from the referenceMap.
          * Therefore, we can help the decision-making by passing "mode". This can either be
          * "parent" or "dependent", which will then force a call to findParentRow and findDependentRowset,
          * respectively.
          */
         if (is_null($options['mode'])) {
             // belongs to
             try {
                 $model->getReference($modelName, $options['rule']);
                 $relatedRowset = $row->findParentRow($otherModel, $options['rule'], $conditions);
             } catch (Exception $e) {
                 if (!Garp_Content_Relation_Manager::isInvalidReferenceException($e)) {
                     throw $e;
                 }
                 try {
                     // one to many - one to one
                     // The following line triggers an exception if no reference is available
                     $otherModel->getReference(get_class($model), $options['rule']);
                     $relatedRowset = $row->findDependentRowset($otherModel, $options['rule'], $conditions);
                 } catch (Exception $e) {
                     if (!Garp_Content_Relation_Manager::isInvalidReferenceException($e)) {
                         throw $e;
                     }
                     $bindingModel = $model->getBindingModel($modelName);
                     $relatedRowset = $row->findManyToManyRowset($otherModel, $bindingModel, $options['rule2'], $options['rule'], $conditions);
                 }
             }
         } else {
             switch ($options['mode']) {
                 case 'parent':
                     $relatedRowset = $row->findParentRow($otherModel, $options['rule'], $conditions);
                     break;
                 case 'dependent':
                     $relatedRowset = $row->findDependentRowset($otherModel, $options['rule'], $conditions);
                     break;
                 default:
                     throw new Garp_Model_Exception('Invalid value for "mode" given. Must be either "parent" or ' . '"dependent", but "' . $options['mode'] . '" was given.');
                     break;
             }
         }
     }
     // Reset the cacheQueries value. It's a static property,
     // so leaving it FALSE will affect all future fetch() calls to this
     // model. Not good.
     $otherModel->setCacheQueries($originalCacheQueriesFlag);
     return $relatedRowset;
 }