Esempio n. 1
0
 /**
  * Update row.
  *
  * @throws Exception
  *
  * @return System\DbRecord\DbRecord
  */
 public function update(DbRecord $record)
 {
     if (!$record->isRecordExisting()) {
         throw new \Nette\InvalidStateException("Only existing row can be updated.");
     }
     $engine = $this->getConnection();
     if ($record->isDirty()) {
         try {
             if (isset($record->belongsToCollection)) {
                 // patrim do kolekce a již jsem uložen v databázi! logicky musím mít nastaven relační klíč a musí být shodný s rodičem kolekce
                 $collection = $record->belongsToCollection;
                 $collectionOwner = $collection->getBelongsToRecord();
                 $relationId = $collection->getAssociation()->getRelationId();
                 $pk = $collectionOwner::config()->getPrimaryColumn();
                 if (!isset($record->{$relationId})) {
                     throw new \LogicException("Member of collection can not be save without known id of owner of collection!");
                 } else {
                     if (!isset($collectionOwner->{$pk}) || $record->{$relationId} != $collectionOwner->{$pk}) {
                         throw new \LogicException("Member of collection has different id then owner of collection!");
                     }
                 }
             }
             $this->onBeforeUpdate($record);
             if (!$record->isValid(EntityValidator::VALIDATION_UPDATE)) {
                 $errors = $record->getErrors();
                 if (count($errors)) {
                     $msg = current($errors);
                     throw new Exception($msg[0]);
                 } else {
                     throw new Exception("Undefined validator exception!");
                 }
             }
             $this->onBeforeUpdateAfterValidation($record);
             $values = $record->getModifiedValues(true);
             $config = $this->getConfig();
             $topicIndex = $record::topicIndex();
             if ($config->isPrimaryAutoincrement()) {
                 $pk = $config->getPrimaryColumn();
                 unset($values[$pk . "%" . $config->getType($pk)]);
             }
             if (!$engine->inTransaction()) {
                 $doCommit = true;
                 $engine->begin();
             }
             $table = $record::table();
             //	Zmana rodice -----------------------------------------------
             if (isset($values['idParent%i']) && !isset($values['ord%i'])) {
                 $values['ord%i'] = $engine->select('COUNT(*)')->from($table)->where('idParent = %i', $values['idParent%i'])->fetchSingle();
             }
             //	Zmena poradi -----------------------------------------------
             if (isset($values['ord%i'])) {
                 $ord = $values['ord%i'];
                 //	Stare umisteni
                 if (!isset($old)) {
                     $old = $engine->select('sx, dx, lvl, ord, idParent, ' . $topicIndex)->select('id, name')->from($table)->where('id = %i', $record->id)->fetch();
                 }
                 //	Bug, $record->parent v pripade neexistujucihi parenta mel yvhodit vyjimku, ne nacist nesmysl.
                 if (empty($record->idParent)) {
                     $record->idParent = $old->idParent;
                 }
                 if (!isset($parent)) {
                     $parent = $record->parent;
                 }
                 if ($ord == $old->ord && $parent->id == $old->idParent) {
                     unset($values['ord%i']);
                     unset($ord);
                 } else {
                     //	Nastavit jako prvni.
                     if (0 === $ord) {
                         //	Jednoduzsi, nastavime na prvni.
                         $record->sx = $values['sx%i'] = $parent->sx + 1;
                     } else {
                         $tmp = $engine->select('sx, dx, idParent')->from($table)->where('idParent = %i', $parent->id)->and('ord = %i', $ord)->fetch();
                         //	Na konec, nebo mimo rozsah.
                         if (false === $tmp) {
                             //	Overit mimo rozsah. Pokud je to posledni, tak je to ok.
                             $tmpOrd = $engine->select('COUNT(*)')->from($table)->where('idParent = %i', $parent->id)->fetchSingle();
                             if ($ord == $tmpOrd) {
                                 $record->ord = $ord = $tmpOrd;
                                 $tmp = (object) array('sx' => $parent->dx, 'dx' => $parent->dx, 'idParent' => $parent->id);
                             } else {
                                 throw new \RangeException("Out of range: {$ord}/{$tmpOrd}.");
                             }
                         }
                         //	Dolu
                         if ($tmp->dx > $old->dx && $tmp->idParent == $old->idParent) {
                             $record->sx = $values['sx%i'] = $tmp->dx + 1;
                         } else {
                             $record->sx = $values['sx%i'] = $tmp->sx;
                         }
                     }
                     $record->dx = $values['dx%i'] = $record->sx + ($old->dx - $old->sx);
                 }
             }
             //	Vytvorit misto ---------------------------------------------
             if (isset($ord)) {
                 $record->{$topicIndex} = $parent->{$topicIndex};
                 // ???
                 $range = $this->openSpace($engine, $table, $topicIndex, $record, true);
                 //	Posunout zaznam vcetne potomku -------------------------
                 //	Posunuli jsme sebe
                 $selfshift = 0;
                 if ($old->sx >= $record->sx && $old->{$topicIndex} == $record->{$topicIndex}) {
                     $selfshift = $range;
                 }
                 // update left
                 $engine->update($table, array('sx%sql' => "(sx - " . ($old->sx + $selfshift) . ") + {$record->sx}", $topicIndex . '%i' => $parent->{$topicIndex}))->where("sx >= %i", $old->sx + $selfshift)->and("sx < %i", $old->dx + $selfshift)->and($topicIndex . " = %i", $old->{$topicIndex})->execute();
                 // update right
                 $engine->update($table, array('dx%sql' => "(dx - " . ($old->dx + $selfshift) . ") + {$record->dx}", $topicIndex . '%i' => $parent->{$topicIndex}))->where("dx <= %i", $old->dx + $selfshift)->and("dx > %i", $old->sx + $selfshift)->and('%sql', "({$topicIndex} = {$old->{$topicIndex}} OR {$topicIndex} = {$record->{$topicIndex}})")->execute();
             }
             //	Ulozit zaznam ----------------------------------------------
             if (count($values)) {
                 $engine->update($table, $values)->where('%and', $record->getPrimaryCondition())->execute();
             }
             //	Zacelit diru -----------------------------------------------
             if (isset($ord)) {
                 $this->closeSpace($engine, $table, $topicIndex, $old->sx + $selfshift, $old->dx + $selfshift, $old->{$topicIndex});
                 if ($record->sx >= $old->sx) {
                     $record->sx -= $range;
                     $record->dx -= $range;
                 }
             }
             if (isset($parent)) {
                 $record->lvl = $parent->lvl + 1;
             }
             if (isset($old)) {
                 //	Opravit ord --------------------------------------------
                 //	Sourozence, ktere jsem opustil.
                 $engine->update($table, array('ord%sql' => 'ord - 1'))->where('idParent = %i', $old->idParent)->and('id != %i', $record->id)->and('ord >= %i', $old->ord)->execute();
                 //	Sourozence, kam jsem se vetrel. To by mela zajistit openSpace().
                 $engine->update($table, array('ord%sql' => "ord + 1"))->where('idParent = %i', $record->idParent)->and('id != %i', $record->id)->and('ord >= %i', $record->ord)->execute();
                 //	Opravit lvl	svych vetvy. -------------------------------
                 if ($record->idParent != $old->idParent) {
                     $engine->update($table, array('lvl%sql' => "lvl + ({$record->lvl} - {$old->lvl})"))->where('sx >= %i', $record->sx)->and('dx <= %i', $record->dx)->and($topicIndex . " = %i", $record->{$topicIndex})->execute();
                 }
             }
             //	Naplnit record ---------------------------------------------
             #				if (isset($old)) {
             #
             #				}
             //	Ukoncit transakci ------------------------------------------
             if (isset($doCommit)) {
                 $engine->commit();
             }
         } catch (\DibiException $e) {
             if ($engine->getDriver() instanceof \DibiMySqliDriver) {
                 switch ($e->getCode()) {
                     case \DibiMySqliDriver::ERROR_DUPLICATE_ENTRY:
                         if (preg_match('~Duplicate entry \'([^\']*)\' for key \'([^\']*)\'~', $e->getMessage(), $matches)) {
                             $msg = $record::validator()->translate('v/recordDuplicity', 1, array('{__ENTRY__}' => $matches[1], '{__KEY__}' => $matches[2]));
                             throw new Exception($msg, $e->getCode(), $e, $record);
                         } else {
                             throw new Exception($e->getMessage(), $e->getCode(), $e, $record);
                         }
                         break;
                     default:
                         throw new Exception($e->getMessage(), $e->getCode(), $e, $record);
                         break;
                 }
             } else {
                 throw new \Nette\NotImplementedException('exceptions only for mysql.');
             }
         }
         //	Zmeny uplatneny.
         $record->clearModified();
     }
     //	Vse se to tyka take asociaci. -- toto dohledat.
     foreach ($record->getAssociations() as $key => $associationObject) {
         // treba neexistuje, kdyz neni povinna vytvori se NULL
         if (!$associationObject) {
             continue;
         }
         $associationObject->save();
     }
     return $engine->affectedRows();
 }
Esempio n. 2
0
 /**
  * Update row.
  *
  * @throws Exception
  *
  * @return System\DbRecord\DbRecord
  */
 public function update(DbRecord $record)
 {
     if (!$record->isRecordExisting()) {
         throw new \Nette\InvalidStateException("Only existing row can be updated.");
     }
     $engine = $this->getConnection();
     if (!$engine->inTransaction()) {
         $doCommit = true;
         $engine->begin();
     }
     if ($record->isDirty()) {
         try {
             if (isset($record->belongsToCollection)) {
                 //	patrim do kolekce a již jsem uložen v databázi! logicky
                 //	predek uz musi met nastaveny PK ...
                 $collection = $record->belongsToCollection;
                 $localId = $collection->getAssociation()->getForeignId();
                 $collectionOwner = $collection->getBelongsToRecord();
                 $ownerId = $collection->getAssociation()->getLocalId();
                 if (!isset($collectionOwner->{$ownerId})) {
                     throw new \LogicException("Collection owner has not primary key, associations can not be updated! {$ownerId}");
                 }
                 //	... i ja musím mít nastaven relační klíč...
                 if (!isset($record->{$localId})) {
                     throw new \LogicException("Member of collection can not be save without known primary key of owner of collection! {$localId}");
                 }
                 //	... a musí být shodný s rodičem kolekce.
                 if ($record->{$localId} != $collectionOwner->{$ownerId}) {
                     throw new \LogicException("Member of collection has different id then owner of collection! [" . $record->{$localId} . " / " . $collectionOwner->{$ownerId} . "]");
                 }
             }
             $this->onBeforeUpdate($record);
             if (!$record->isValid(EntityValidator::VALIDATION_UPDATE)) {
                 $errors = $record->getErrors();
                 if (count($errors)) {
                     $msg = current($errors);
                     throw new Exception($msg[0]);
                 } else {
                     throw new Exception("Undefined validator exception!");
                 }
             }
             $this->onBeforeUpdateAfterValidation($record);
             $values = $record->getModifiedValues(true);
             $config = $this->getConfig();
             if ($config->isPrimaryAutoincrement()) {
                 $pk = $config->getPrimaryColumn();
                 unset($values[$pk . "%" . $config->getType($pk)]);
             }
             if (count($values)) {
                 $engine->update($record::table(), $values)->where('%and', $record->getPrimaryCondition())->execute();
             }
         } catch (\DibiException $e) {
             if ($engine->getDriver() instanceof \DibiMySqliDriver) {
                 switch ($e->getCode()) {
                     case \DibiMySqliDriver::ERROR_DUPLICATE_ENTRY:
                         if (preg_match('~Duplicate entry \'([^\']*)\' for key \'([^\']*)\'~', $e->getMessage(), $matches)) {
                             $msg = $record::validator()->translate('v/recordDuplicity', 1, array('{__ENTRY__}' => $matches[1], '{__KEY__}' => $matches[2]));
                             throw new Exception($msg, $e->getCode(), $e);
                         } else {
                             throw $e;
                         }
                         break;
                     default:
                         throw $e;
                 }
             } else {
                 throw new \LogicException('implementovane pouze pro mysql.');
             }
         }
         $record->clearModified();
     }
     foreach ($record->getAssociations() as $key => $associationObject) {
         // treba neexistuje, kdyz neni povinna vytvori se NULL
         if (!$associationObject) {
             continue;
         }
         $associationObject->save();
     }
     $this->onAfterUpdate($record);
     if (isset($doCommit)) {
         $engine->commit();
     }
     // set action / pravdepodobne probehla v poradku
     $record->lastAction('u');
     $record->setLastAffectedRows($engine->affectedRows());
     return $record;
 }