Pimcore\Model\Object\AbstractObject::save PHP Method

save() public method

public save ( )
    public function save()
    {
        $isUpdate = false;
        if ($this->getId()) {
            $isUpdate = true;
            \Pimcore::getEventManager()->trigger("object.preUpdate", $this);
        } else {
            \Pimcore::getEventManager()->trigger("object.preAdd", $this);
        }
        $this->correctPath();
        // we wrap the save actions in a loop here, so that we can restart the database transactions in the case it fails
        // if a transaction fails it gets restarted $maxRetries times, then the exception is thrown out
        // this is especially useful to avoid problems with deadlocks in multi-threaded environments (forked workers, ...)
        $maxRetries = 5;
        for ($retries = 0; $retries < $maxRetries; $retries++) {
            // be sure that unpublished objects in relations are saved also in frontend mode, eg. in importers, ...
            $hideUnpublishedBackup = self::getHideUnpublished();
            self::setHideUnpublished(false);
            $this->beginTransaction();
            try {
                if (!in_array($this->getType(), self::$types)) {
                    throw new \Exception("invalid object type given: [" . $this->getType() . "]");
                }
                if (!$isUpdate) {
                    $this->getDao()->create();
                }
                // get the old path from the database before the update is done
                $oldPath = null;
                if ($isUpdate) {
                    $oldPath = $this->getDao()->getCurrentFullPath();
                }
                // if the old path is different from the new path, update all children
                // we need to do the update of the children's path before $this->update() because the
                // inheritance helper needs the correct paths of the children in InheritanceHelper::buildTree()
                $updatedChildren = [];
                if ($oldPath && $oldPath != $this->getRealFullPath()) {
                    $this->getDao()->updateWorkspaces();
                    $updatedChildren = $this->getDao()->updateChildsPaths($oldPath);
                }
                $this->update();
                self::setHideUnpublished($hideUnpublishedBackup);
                $this->commit();
                break;
                // transaction was successfully completed, so we cancel the loop here -> no restart required
            } catch (\Exception $e) {
                try {
                    $this->rollBack();
                } catch (\Exception $er) {
                    // PDO adapter throws exceptions if rollback fails
                    Logger::info($er);
                }
                if ($e instanceof Model\Element\ValidationException) {
                    throw $e;
                }
                // set "HideUnpublished" back to the value it was originally
                self::setHideUnpublished($hideUnpublishedBackup);
                // we try to start the transaction $maxRetries times again (deadlocks, ...)
                if ($retries < $maxRetries - 1) {
                    $run = $retries + 1;
                    $waitTime = 100000;
                    // microseconds
                    Logger::warn("Unable to finish transaction (" . $run . ". run) because of the following reason '" . $e->getMessage() . "'. --> Retrying in " . $waitTime . " microseconds ... (" . ($run + 1) . " of " . $maxRetries . ")");
                    usleep($waitTime);
                    // wait specified time until we restart the transaction
                } else {
                    // if the transaction still fail after $maxRetries retries, we throw out the exception
                    Logger::error("Finally giving up restarting the same transaction again and again, last message: " . $e->getMessage());
                    throw $e;
                }
            }
        }
        $additionalTags = [];
        if (isset($updatedChildren) && is_array($updatedChildren)) {
            foreach ($updatedChildren as $objectId) {
                $tag = "object_" . $objectId;
                $additionalTags[] = $tag;
                // remove the child also from registry (internal cache) to avoid path inconsistencies during long running scripts, such as CLI
                \Zend_Registry::set($tag, null);
            }
        }
        $this->clearDependentCache($additionalTags);
        if ($isUpdate) {
            \Pimcore::getEventManager()->trigger("object.postUpdate", $this);
        } else {
            \Pimcore::getEventManager()->trigger("object.postAdd", $this);
        }
        return $this;
    }

Usage Example

Example #1
0
 /**
  * Verify password. Optionally re-hash the password if needed.
  *
  * Re-hash will be performed if PHP's password_hash default params (algorithm, cost) differ
  * from the ones which were used to create the hash (e.g. cost was increased from 10 to 12).
  * In this case, the hash will be re-calculated with the new parameters and saved back to the object.
  *
  * @param $password
  * @param Object\AbstractObject $object
  * @param bool|true $updateHash
  * @return bool
  */
 public function verifyPassword($password, Object\AbstractObject $object, $updateHash = true)
 {
     $getter = 'get' . ucfirst($this->getName());
     $setter = 'set' . ucfirst($this->getName());
     $objectHash = $object->{$getter}();
     if (null === $objectHash || empty($objectHash)) {
         return false;
     }
     $result = false;
     if ($this->getAlgorithm() === static::HASH_FUNCTION_PASSWORD_HASH) {
         $result = true === password_verify($password, $objectHash);
         if ($result && $updateHash) {
             // password needs rehash (e.g PASSWORD_DEFAULT changed to a stronger algorithm)
             if (true === password_needs_rehash($objectHash, PASSWORD_DEFAULT)) {
                 $newHash = $this->calculateHash($password);
                 $object->{$setter}($newHash);
                 $object->save();
             }
         }
     } else {
         $hash = $this->calculateHash($password);
         $result = $hash === $objectHash;
     }
     return $result;
 }