Last active
July 29, 2020 07:46
-
-
Save stalniy/1dd385d00bb34148d86dd0483468577f to your computer and use it in GitHub Desktop.
Extended Doctrine 1.2 Query class with support for multiInsert
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class sjQuery extends Doctrine_Query { | |
protected | |
$_insert_queue_size = 0, | |
$_insert_queue = array(), | |
$_last_insert_ids = array(), | |
$_relations_queue = array(); | |
public function queueSize(){ | |
return count($this->_insert_queue); | |
} | |
public function setQueue(array $queue){ | |
$this->_insert_queue = $queue; | |
return $this; | |
} | |
public function pushToQueue($data){ | |
$this->_insert_queue[] = $data; | |
return $this; | |
} | |
public function popFromQueue(){ | |
array_pop($this->_insert_queue); | |
return $this; | |
} | |
public function multipleInsert($tableName){ | |
if (!isset($this->_insert_queue[0])) { | |
return false; | |
} | |
$this->reset(); | |
$table = Doctrine_Core::getTable($tableName); | |
return $this->prepareInsert($table); | |
} | |
public function getLastInsertIds(Doctrine_Table $table) { | |
if (!empty($this->_last_insert_ids)) { | |
return $this->_last_insert_ids; | |
} | |
$last_id = $this->_conn->lastInsertId('id'); | |
$count = $this->_insert_queue_size; | |
$ids = array(); | |
if ($count && $count != 1) { | |
$idFieldName = $table->getIdentifier(); | |
$q = $table->createQuery('ls') | |
->select('ls.' . $idFieldName . ' as id') | |
->where('ls.' . $idFieldName . ' <= ?', $last_id + $count - 1) | |
->orderBy('ls.' . $idFieldName . ' DESC') | |
->limit($count); | |
$data = $q->execute(array(), Doctrine_Core::HYDRATE_SCALAR); | |
if (empty($data)) { | |
throw new Doctrine_Connection_Exception("Failed to get last insert ids for " . get_class($table) . ". Before using this method you must execute insert"); | |
} | |
$i = count($data); | |
$k = 0; | |
while ($i--) { | |
$id = $data[$i]['ls_id']; | |
$this->_insert_queue[$k++][$idFieldName] = $id; | |
$ids[] = $id; | |
} | |
} else { | |
$ids[] = $last_id; | |
} | |
return $this->_last_insert_ids = $ids; | |
} | |
protected function prepareQueueValues(Doctrine_Table $table) { | |
$relations = array(); | |
// column names are specified as array keys | |
$cols = array(); | |
$a = $b = array(); | |
$fields = reset($this->_insert_queue); | |
foreach ($fields as $fieldName => $value) { | |
if (is_array($value) && $table->hasRelation($fieldName)) { | |
$relations[] = $fieldName; | |
} else { | |
$cols[] = $this->_conn->quoteIdentifier($table->getColumnName($fieldName)); | |
$a[] = '?'; | |
} | |
} | |
$a = '('.implode(',', $a).')'; | |
$b = array_fill(0, count($this->_insert_queue), $a); | |
$this->prepareRelations($table, $relations); | |
$values = array_map('array_values', $this->_insert_queue); | |
$values = call_user_func_array('array_merge', $values); | |
return array( | |
'fields' => $cols, | |
'values' => $b, | |
'params' => $values | |
); | |
} | |
protected function prepareRelations(Doctrine_Table $table, array $relations) { | |
if (empty($relations)) { | |
return $this; | |
} | |
foreach ($this->_insert_queue as $k => &$row) { | |
foreach ($relations as &$relation) { | |
$this->_relations_queue[$relation][] = $row[$relation]; | |
unset($this->_insert_queue[$k][$relation]); | |
} | |
} | |
return $this; | |
} | |
protected function insertRelationDataFor(Doctrine_Table $table) { | |
$ids = $this->getLastInsertIds($table); | |
$return = true; | |
foreach ($this->_relations_queue as $relation => &$value) { | |
$relationObj = $table->getRelation($relation); | |
$foreignColumn = $relationObj->getForeignColumnName(); | |
$localColumn = $relationObj->getLocalColumnName(); | |
foreach ($value as $k => &$row) { | |
$row = array_values($row); | |
foreach ($row as $i => &$subRow) { | |
$subRow[$foreignColumn] = &$this->_insert_queue[$k][$localColumn]; | |
} | |
} | |
$value = call_user_func_array('array_merge', $value); | |
#echo "<pre>Relation ", $relation, "\n"; | |
#print_r($value); | |
#echo "\n\n"; | |
#continue; | |
$result = Doctrine_Query::create() | |
->setQueue($value) | |
->multipleInsert($relationObj->getClass()); | |
$return = $return && $result; | |
if (!$return) { | |
throw new Doctrine_Relation_Exception(sprintf( | |
"Can not insert relation data (%s) for %s table", | |
$relationObj->getTable()->getTableName(), | |
$table->getTableName() | |
)); | |
} | |
unset($this->_relations_queue[$relation]); | |
} | |
$this->_relations_queue = array(); | |
#exit; | |
return $return; | |
} | |
protected function prepareInsert(Doctrine_Table $table){ | |
$tableName = $table->getTableName(); | |
$data = $this->prepareQueueValues($table); | |
try { | |
$this->_conn->beginTransaction(); | |
// build the statement | |
$query = 'INSERT INTO ' . $this->_conn->quoteIdentifier($tableName) | |
. ' (' . implode(', ', $data['fields']) . ')' | |
. ' VALUES ' . implode(', ', $data['values']); | |
$result = $this->_conn->exec($query, $data['params']); | |
$this->_insert_queue_size = $this->queueSize(); | |
if ($result && !empty($this->_relations_queue)) { | |
$result = $result && $this->insertRelationDataFor($table); | |
} | |
if (!$result) { | |
throw new Doctrine_Connection_Exception("Failed inserting records in " . get_class($table)); | |
} | |
$this->_conn->commit(); | |
$this->_insert_queue = array(); | |
return $result; | |
} catch (Exception $e) { | |
$this->_conn->rollBack(); | |
throw $e; | |
} | |
} | |
public function reset() { | |
$this->_relations_queue = array(); | |
$this->_last_insert_ids = array(); | |
return $this; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment