Skip to content

Instantly share code, notes, and snippets.

@stalniy
Last active July 29, 2020 07:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save stalniy/1dd385d00bb34148d86dd0483468577f to your computer and use it in GitHub Desktop.
Save stalniy/1dd385d00bb34148d86dd0483468577f to your computer and use it in GitHub Desktop.
Extended Doctrine 1.2 Query class with support for multiInsert
<?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