Example #1
0
 /**
  * Add a hasAndBelongsToMany filter to a Zend_Db_Select object.
  * Example query:
  * SELECT *
  * FROM tags
  * LEFT JOIN tags_users ON tags_users.tag_id = tags.id AND user_id = 35
  * INNER JOIN `users` ON users.id = tags_users.user_id
  * WHERE user_id 35 // in the case of negation, this'll be "WHERE user_id IS NULL"
  *
  * @param array $options Collection of options containing;
  * ['select']       Zend_Db_Select  The select object
  * ['filterModel']  Garp_Model_Db   The filtering model
  * ['filterColumn'] string          The column used as the query filter
  * ['filterValue']  mixed           The value used as the query filter
  * ['negation']     bool            Wether the query should include or exclude
  *                                  matches found by $filterValue
  * ['bidirectional'] bool           Wether homophile relationships should be queried
  *                                  bidirectionally
  * @return void
  */
 protected function _addHasAndBelongsToManyClause(array $options)
 {
     if (!isset($options['bindingModel'])) {
         $modelNames = array($this->_model->getNameWithoutNamespace(), $options['filterModel']->getNameWithoutNamespace());
         sort($modelNames);
         $bindingModelName = 'Model_' . implode('', $modelNames);
     } else {
         $bindingModelName = 'Model_' . $options['bindingModel'];
     }
     $bindingModel = new $bindingModelName();
     $thisTableName = $this->_getTableName($this->_model);
     $bindingModelTable = $bindingModel->getName();
     $reference = $bindingModel->getReference(get_class($this->_model));
     foreach ($reference['refColumns'] as $i => $column) {
         if ($column === $options['filterColumn']) {
             $bindingModelForeignKeyField = $reference['columns'][$i];
             $foreignKeyField = $column;
             break;
         }
     }
     $reference = $bindingModel->getReference(get_class($options['filterModel']), $this->_findSecondRuleKeyForHomophiles($options['filterModel'], $bindingModel));
     foreach ($reference['refColumns'] as $i => $column) {
         if ($column === $options['filterColumn']) {
             $filterField = $reference['columns'][$i];
             break;
         }
     }
     $bindingCondition = $bindingModelTable . '.' . $bindingModelForeignKeyField . ' = ' . $thisTableName . '.' . $foreignKeyField;
     $bindingCondition .= $bindingModel->getAdapter()->quoteInto(' AND ' . $bindingModelTable . '.' . $filterField . ' = ?', $options['filterValue']);
     if ($this->_isHomophile($options['filterModel']) && array_get($options, 'bidirectional')) {
         $bindingCondition .= ' OR ' . $bindingModelTable . '.' . $filterField . ' = ' . $thisTableName . '.' . $foreignKeyField;
         $bindingCondition .= $bindingModel->getAdapter()->quoteInto(' AND ' . $bindingModelTable . '.' . $bindingModelForeignKeyField . ' = ?', $options['filterValue']);
     }
     // Add columns of bindingTable to the query (namespaced using dot)
     $tmpBindingColumns = $bindingModel->info(Zend_Db_Table::COLS);
     $bindingColumns = array();
     $weighableColumns = array();
     if ($weighable = $bindingModel->getObserver('Weighable')) {
         $weighableColumns = $weighable->getWeightColumns();
     }
     foreach ($tmpBindingColumns as $bc) {
         // Exclude foreign key fields
         if (in_array($bc, array($bindingModelForeignKeyField, $filterField))) {
             continue;
         }
         // Exclude columns generated by a Weighable behavior
         if (in_array($bc, $weighableColumns)) {
             continue;
         }
         $bindingColumns[$bindingModel->getNameWithoutNamespace() . '.' . $bc] = $bc;
     }
     $options['select']->joinLeft($bindingModelTable, $bindingCondition, $bindingColumns);
     if ($options['negation']) {
         $options['select']->where($bindingModelTable . '.' . $filterField . ' IS NULL');
     } else {
         $options['select']->where($bindingModelTable . '.' . $filterField . ' = ?', $options['filterValue']);
         if ($this->_isHomophile($options['filterModel']) && array_get($options, 'bidirectional')) {
             $options['select']->orWhere($bindingModelTable . '.' . $bindingModelForeignKeyField . ' = ?', $options['filterValue']);
             $options['select']->group('id');
         }
     }
     // Allow behaviors to modify the SELECT object
     $bindingModel->notifyObservers('beforeFetch', array($bindingModel, $options['select']));
 }