Pimcore\Model\Document::save PHP Method

save() public method

Save the document.
public save ( ) : Document
return Document
    public function save()
    {
        $isUpdate = false;
        if ($this->getId()) {
            $isUpdate = true;
            \Pimcore::getEventManager()->trigger("document.preUpdate", $this);
        } else {
            \Pimcore::getEventManager()->trigger("document.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++) {
            $this->beginTransaction();
            try {
                // set date
                $this->setModificationDate(time());
                if (!$this->getCreationDate()) {
                    $this->setCreationDate(time());
                }
                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();
                }
                $this->update();
                // if the old path is different from the new path, update all children
                $updatedChildren = [];
                if ($oldPath && $oldPath != $this->getRealFullPath()) {
                    $this->getDao()->updateWorkspaces();
                    $updatedChildren = $this->getDao()->updateChildsPaths($oldPath);
                }
                $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::error($er);
                }
                // 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
                    throw $e;
                }
            }
        }
        $additionalTags = [];
        if (isset($updatedChildren) && is_array($updatedChildren)) {
            foreach ($updatedChildren as $documentId) {
                $tag = "document_" . $documentId;
                $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("document.postUpdate", $this);
        } else {
            \Pimcore::getEventManager()->trigger("document.postAdd", $this);
        }
        return $this;
    }

Usage Example

コード例 #1
0
ファイル: Manager.php プロジェクト: pimcore/pimcore
 /**
  *
  * Performs an action
  *
  * @param mixed $actionName
  * @param array $formData
  * @throws \Exception
  */
 public function performAction($actionName, $formData = [])
 {
     //store the current action data
     $this->setActionData($formData);
     \Pimcore::getEventManager()->trigger("workflowmanagement.preAction", $this, ['actionName' => $actionName]);
     //refresh the local copy after the event
     $formData = $this->getActionData();
     $actionConfig = $this->workflow->getActionConfig($actionName, $this->getElementStatus());
     $additional = $formData['additional'];
     //setup event listeners
     $this->registerActionEvents($actionConfig);
     //setup an array to hold the additional data that is not saved via a setterFn
     $actionNoteData = [];
     //process each field in the additional fields configuration
     if (isset($actionConfig['additionalFields']) && is_array($actionConfig['additionalFields'])) {
         foreach ($actionConfig['additionalFields'] as $additionalFieldConfig) {
             /**
             * Additional Field example
             * [
                             'name' => 'dateLastContacted',
                             'fieldType' => 'date',
                             'label' => 'Date of Conversation',
                             'required' => true,
                             'setterFn' => ''
                             ]
             */
             $fieldName = $additionalFieldConfig['name'];
             //check required
             if ($additionalFieldConfig['required'] && empty($additional[$fieldName])) {
                 throw new \Exception("Workflow::performAction, fieldname [{$fieldName}] required for action [{$actionName}]");
             }
             //work out whether or not to set the value directly to the object or to add it to the note data
             if (!empty($additionalFieldConfig['setterFn'])) {
                 $setter = $additionalFieldConfig['setterFn'];
                 try {
                     //todo check here that the setter is being called on an Object
                     //TODO check that the field has a fieldType, (i.e if a workflow config has getter then the field should only be a pimcore tag and therefore 'fieldType' rather than 'type'.
                     //otherwise we could be erroneously setting pimcore fields
                     $additional[$fieldName] = Workflow\Service::getDataFromEditmode($additional[$fieldName], $additionalFieldConfig['fieldType']);
                     $this->element->{$setter}($additional[$fieldName]);
                 } catch (\Exception $e) {
                     Logger::error($e->getMessage());
                     throw new \Exception("Workflow::performAction, cannot set fieldname [{$fieldName}] using setter [{$setter}] in action [{$actionName}]");
                 }
             } else {
                 $actionNoteData[] = Workflow\Service::createNoteData($additionalFieldConfig, $additional[$fieldName]);
             }
         }
     }
     //save the old state and status in the form so that we can reference it later
     $formData['oldState'] = $this->getElementState();
     $formData['oldStatus'] = $this->getElementStatus();
     if ($this->element instanceof Concrete || $this->element instanceof Document\PageSnippet) {
         if (!$this->workflow->getAllowUnpublished() || in_array($this->getElementStatus(), $this->workflow->getPublishedStatuses())) {
             $this->element->setPublished(true);
             if ($this->element instanceof Concrete) {
                 $this->element->setOmitMandatoryCheck(false);
             }
             $task = 'publish';
         } else {
             $this->element->setPublished(false);
             if ($this->element instanceof Concrete) {
                 $this->element->setOmitMandatoryCheck(true);
             }
             $task = 'unpublish';
         }
     } else {
         //all other elements do not support published or unpublished
         $task = "publish";
     }
     try {
         $response = \Pimcore::getEventManager()->trigger("workflowmanagement.action.before", $this, ['actionConfig' => $actionConfig, 'data' => $formData]);
         //todo add some support to stop the action given the result from the event
         $this->element->setUserModification($this->user->getId());
         if ($task === "publish" && $this->element->isAllowed("publish") || $task === "unpublish" && $this->element->isAllowed("unpublish")) {
             $this->element->save();
         } elseif ($this->element instanceof Concrete || $this->element instanceof Document\PageSnippet) {
             $this->element->saveVersion();
         } else {
             throw new \Exception("Operation not allowed for this element");
         }
         //transition the element
         $this->setElementState($formData['newState']);
         $this->setElementStatus($formData['newStatus']);
         // record a note against the object to show the transition
         $decorator = new Workflow\Decorator($this->workflow);
         $description = $formData['notes'];
         // create a note for this action
         $note = Workflow\Service::createActionNote($this->element, $decorator->getNoteType($actionName, $formData), $decorator->getNoteTitle($actionName, $formData), $description, $actionNoteData);
         //notify users
         if (isset($actionConfig['notificationUsers']) && is_array($actionConfig['notificationUsers'])) {
             Workflow\Service::sendEmailNotification($actionConfig['notificationUsers'], $note);
         }
         \Pimcore::getEventManager()->trigger("workflowmanagement.action.success", $this, ['actionConfig' => $actionConfig, 'data' => $formData]);
     } catch (\Exception $e) {
         \Pimcore::getEventManager()->trigger("workflowmanagement.action.failure", $this, ['actionConfig' => $actionConfig, 'data' => $formData, 'exception' => $e]);
     }
     $this->unregisterActionEvents();
     \Pimcore::getEventManager()->trigger("workflowmanagement.postAction", $this, ['actionName' => $actionName]);
 }