/** * isIdentifiable * returns whether or not a given data row is identifiable (it contains * all primary key fields specified in the second argument) * * @param array $row * @param Doctrine_Table $table * @return boolean */ public function isIdentifiable(array $row, Doctrine_Table $table) { $primaryKeys = $table->getIdentifierColumnNames(); if (is_array($primaryKeys)) { foreach ($primaryKeys as $id) { if (!isset($row[$id])) { return false; } } } else { if (!isset($row[$primaryKeys])) { return false; } } return true; }
/** * Updates table row(s) with specified data. * * @throws Doctrine_Connection_Exception if something went wrong at the database level * @param Doctrine_Table $table The table to insert data into * @param array $values An associative array containing column-value pairs. * Values can be strings or Doctrine_Expression instances. * @return integer the number of affected rows. Boolean false if empty value array was given, */ public function update(Doctrine_Table $table, array $fields, array $identifier) { if (empty($fields)) { return false; } $set = array(); foreach ($fields as $fieldName => $value) { if ($value instanceof Doctrine_Expression) { $set[] = $this->quoteIdentifier($table->getColumnName($fieldName)) . ' = ' . $value->getSql(); unset($fields[$fieldName]); } else { $set[] = $this->quoteIdentifier($table->getColumnName($fieldName)) . ' = ?'; } } $params = array_merge(array_values($fields), array_values($identifier)); $sql = 'UPDATE ' . $this->quoteIdentifier($table->getTableName()) . ' SET ' . implode(', ', $set) . ' WHERE ' . implode(' = ? AND ', $this->quoteMultipleIdentifier($table->getIdentifierColumnNames())) . ' = ?'; return $this->exec($sql, $params); }
/** * Creates the SQL for Oracle that can be used in the subquery for the limit-subquery * algorithm. */ public function modifyLimitSubquery(Doctrine_Table $rootTable, $query, $limit = false, $offset = false, $isManip = false) { // NOTE: no composite key support $columnNames = $rootTable->getIdentifierColumnNames(); if (count($columnNames) > 1) { throw new Doctrine_Connection_Exception("Composite keys in LIMIT queries are " . "currently not supported."); } $column = $columnNames[0]; return $this->_createLimitSubquery($query, $limit, $offset, $column); }
/** * Completes the given definition * * @param array $def definition array to be completed * @return array completed definition array * @todo Description: What does it mean to complete a definition? What is done (not how)? * Refactor (too long & nesting level) */ public function completeDefinition($def) { $conn = $this->_table->getConnection(); $def['table'] = $this->getImpl($def['class']); $def['localTable'] = $this->_table; $def['class'] = $def['table']->getComponentName(); $foreignClasses = array_merge($def['table']->getOption('parents'), array($def['class'])); $localClasses = array_merge($this->_table->getOption('parents'), array($this->_table->getComponentName())); $localIdentifierColumnNames = $this->_table->getIdentifierColumnNames(); $localIdentifierCount = count($localIdentifierColumnNames); $localIdColumnName = array_pop($localIdentifierColumnNames); $foreignIdentifierColumnNames = $def['table']->getIdentifierColumnNames(); $foreignIdColumnName = array_pop($foreignIdentifierColumnNames); if (isset($def['local'])) { $def['local'] = $def['localTable']->getColumnName($def['local']); if (!isset($def['foreign'])) { // local key is set, but foreign key is not // try to guess the foreign key if ($def['local'] === $localIdColumnName) { $def['foreign'] = $this->guessColumns($localClasses, $def['table']); } else { // the foreign field is likely to be the // identifier of the foreign class $def['foreign'] = $foreignIdColumnName; $def['localKey'] = true; } } else { $def['foreign'] = $def['table']->getColumnName($def['foreign']); if ($localIdentifierCount == 1) { if ($def['local'] == $localIdColumnName && isset($def['owningSide']) && $def['owningSide'] === true) { $def['localKey'] = true; } else { if ($def['local'] !== $localIdColumnName && $def['type'] == Doctrine_Relation::ONE) { $def['localKey'] = true; } } } else { if ($localIdentifierCount > 1 && !isset($def['localKey'])) { // It's a composite key and since 'foreign' can not point to a composite // key currently, we know that 'local' must be the foreign key. $def['localKey'] = true; } } } } else { if (isset($def['foreign'])) { $def['foreign'] = $def['table']->getColumnName($def['foreign']); // local key not set, but foreign key is set // try to guess the local key if ($def['foreign'] === $foreignIdColumnName) { $def['localKey'] = true; try { $def['local'] = $this->guessColumns($foreignClasses, $this->_table); } catch (Doctrine_Relation_Exception $e) { $def['local'] = $localIdColumnName; } } else { $def['local'] = $localIdColumnName; } } else { // neither local or foreign key is being set // try to guess both keys $conn = $this->_table->getConnection(); // the following loops are needed for covering inheritance foreach ($localClasses as $class) { $table = $conn->getTable($class); $identifierColumnNames = $table->getIdentifierColumnNames(); $idColumnName = array_pop($identifierColumnNames); $column = strtolower($table->getComponentName()) . '_' . $idColumnName; foreach ($foreignClasses as $class2) { $table2 = $conn->getTable($class2); if ($table2->hasColumn($column)) { $def['foreign'] = $column; $def['local'] = $idColumnName; return $def; } } } foreach ($foreignClasses as $class) { $table = $conn->getTable($class); $identifierColumnNames = $table->getIdentifierColumnNames(); $idColumnName = array_pop($identifierColumnNames); $column = strtolower($table->getComponentName()) . '_' . $idColumnName; foreach ($localClasses as $class2) { $table2 = $conn->getTable($class2); if ($table2->hasColumn($column)) { $def['foreign'] = $idColumnName; $def['local'] = $column; $def['localKey'] = true; return $def; } } } // auto-add columns and auto-build relation $columns = array(); foreach ((array) $this->_table->getIdentifierColumnNames() as $id) { // ?? should this not be $this->_table->getComponentName() ?? $column = strtolower($table->getComponentName()) . '_' . $id; $col = $this->_table->getColumnDefinition($id); $type = $col['type']; $length = $col['length']; unset($col['type']); unset($col['length']); unset($col['autoincrement']); unset($col['sequence']); unset($col['primary']); $def['table']->setColumn($column, $type, $length, $col); $columns[] = $column; } if (count($columns) > 1) { $def['foreign'] = $columns; } else { $def['foreign'] = $columns[0]; } $def['local'] = $localIdColumnName; } } return $def; }
/** * Inserts a table row with specified data. * * @param Doctrine_Table $table The table to insert data into. * @param array $values An associative array containing column-value pairs. * Values can be strings or Doctrine_Expression instances. * @return integer the number of affected rows. Boolean false if empty value array was given, */ public function insert(Doctrine_Table $table, array $fields) { $identifiers = $table->getIdentifierColumnNames(); $settingNullIdentifier = false; $fields = array_change_key_case($fields); foreach ($identifiers as $identifier) { $lcIdentifier = strtolower($identifier); if (array_key_exists($lcIdentifier, $fields)) { if (is_null($fields[$lcIdentifier])) { $settingNullIdentifier = true; unset($fields[$lcIdentifier]); } } } // MSSQL won't allow the setting of identifier columns to null, so insert a default record and then update it if ($settingNullIdentifier) { $count = $this->exec('INSERT INTO ' . $this->quoteIdentifier($table->getTableName()) . ' DEFAULT VALUES'); if (!$count) { return $count; } $id = $this->lastInsertId($table->getTableName()); return $this->update($table, $fields, array($id)); } return parent::insert($table, $fields); }