private function queryManyMany($joinTableName, $keys) { $relation = $this->relation; $model = TActiveRecord::model($relation->className); $table = $model->getTableSchema(); $builder = $model->getCommandBuilder(); $schema = $builder->getSchema(); $pkTable = $this->_parent->model->getTableSchema(); if (($joinTable = $builder->getSchema()->getTable($joinTableName)) === null) { throw new TDbException('The relation "' . $relation->name . '" in active record class "' . get_class($this->_parent->model) . '" is not specified correctly. The join table "' . $joinTableName . '" given in the foreign key cannot be found in the database.'); } $fks = preg_split('/[\\s,]+/', $keys, -1, PREG_SPLIT_NO_EMPTY); if (count($fks) !== count($table->primaryKey) + count($pkTable->primaryKey)) { throw new TDbException('The relation "' . $relation->name . '" in active record class "' . get_class($this->_parent->model) . '" is specified with an incomplete foreign key. The foreign key must consist of columns referencing both joining tables.'); } $joinCondition = array(); $map = array(); foreach ($fks as $i => $fk) { if (!isset($joinTable->columns[$fk])) { throw new TDbException('The relation "' . $relation->name . '" in active record class "' . get_class($this->_parent->model) . '" is specified with an invalid foreign key "' . $fk . '". There is no such column in the table "' . $joinTable->name . '".'); } if (isset($joinTable->foreignKeys[$fk])) { list($tableName, $pk) = $joinTable->foreignKeys[$fk]; if (!isset($joinCondition[$pk]) && $schema->compareTableNames($table->rawName, $tableName)) { $joinCondition[$pk] = $table->rawName . '.' . $schema->quoteColumnName($pk) . '=' . $joinTable->rawName . '.' . $schema->quoteColumnName($fk); } else { if (!isset($map[$pk]) && $schema->compareTableNames($pkTable->rawName, $tableName)) { $map[$pk] = $fk; } else { throw new TDbException('The relation "' . $relation->name . '" in active record class "' . get_class($this->_parent->model) . '" is specified with an invalid foreign key "' . $fk . '". The foreign key does not point to either joining table.'); } } } else { if ($i < count($pkTable->primaryKey)) { $pk = is_array($pkTable->primaryKey) ? $pkTable->primaryKey[$i] : $pkTable->primaryKey; $map[$pk] = $fk; } else { $j = $i - count($pkTable->primaryKey); $pk = is_array($table->primaryKey) ? $table->primaryKey[$j] : $table->primaryKey; $joinCondition[$pk] = $table->rawName . '.' . $schema->quoteColumnName($pk) . '=' . $joinTable->rawName . '.' . $schema->quoteColumnName($fk); } } } if ($joinCondition === array() || $map === array()) { throw new TDbException('The relation "' . $relation->name . '" in active record class "' . get_class($this->_parent->model) . '" is specified with an incomplete foreign key. The foreign key must consist of columns referencing both joining tables.'); } $records = $this->_parent->records; $cols = array(); foreach (is_string($pkTable->primaryKey) ? array($pkTable->primaryKey) : $pkTable->primaryKey as $n => $pk) { $name = $joinTable->rawName . '.' . $schema->quoteColumnName($map[$pk]); $cols[$name] = $name . ' AS ' . $schema->quoteColumnName('c' . $n); } $keys = array_keys($records); if (is_array($pkTable->primaryKey)) { foreach ($keys as &$key) { $key2 = unserialize($key); $key = array(); foreach ($pkTable->primaryKey as $pk) { $key[$map[$pk]] = $key2[$pk]; } } } $where = empty($relation->condition) ? '' : ' WHERE (' . $relation->condition . ')'; $group = empty($relation->group) ? '' : ', ' . $relation->group; $having = empty($relation->having) ? '' : ' AND (' . $relation->having . ')'; $order = empty($relation->order) ? '' : ' ORDER BY ' . $relation->order; $sql = 'SELECT ' . $this->relation->select . ' AS ' . $schema->quoteColumnName('s') . ', ' . implode(', ', $cols) . ' FROM ' . $table->rawName . ' INNER JOIN ' . $joinTable->rawName . ' ON (' . implode(') AND (', $joinCondition) . ')' . $where . ' GROUP BY ' . implode(', ', array_keys($cols)) . $group . ' HAVING (' . $builder->createInCondition($joinTable, $map, $keys) . ')' . $having . $order; $command = $builder->getDbConnection()->createCommand($sql); if (is_array($relation->params)) { $builder->bindValues($command, $relation->params); } $stats = array(); foreach ($command->queryAll() as $row) { if (is_array($pkTable->primaryKey)) { $key = array(); foreach ($pkTable->primaryKey as $n => $k) { $key[$k] = $row['c' . $n]; } $stats[serialize($key)] = $row['s']; } else { $stats[$row['c0']] = $row['s']; } } foreach ($records as $pk => $record) { $record->addRelatedRecord($relation->name, isset($stats[$pk]) ? $stats[$pk] : $this->relation->defaultValue, false); } }
/** * Returns the static model of the specified AR class. * @param string $className active record class name. * @return MakeOrgan the static model class */ public static function model($className = __CLASS__) { return parent::model($className); }