/** * 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(); }
/** * 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; }