/**
  * Save the current objects attributes
  *
  * @param boolean $runValidation
  *        should validations be executed on all models before allowing saveAll()
  * @param boolean $hasParentModel
  *        whether this method was called from the top level or by a parent
  *        If false, it means the method was called at the top level
  * @param boolean $fromSaveAll
  *        has the save() call come from saveAll() or not
  * @return boolean
  *        did save() successfully process
  */
 public function save($runValidation = true, $hasParentModel = false, $push = false, $fromSaveAll = false)
 {
     if ($this->getReadOnly() && !$hasParentModel) {
         // return failure if we are at the top of the tree and should not be asking to saveAll
         // not allowed to amend or delete
         $message = 'Attempting to save on ' . Tools::getClassName($this) . ' readOnly model';
         //$this->addActionError($message);
         throw new Exception($message);
     } elseif ($this->getReadOnly() && $hasParentModel) {
         $message = 'Skipping save on ' . Tools::getClassName($this) . ' readOnly model';
         $this->addActionWarning($message);
         return true;
     }
     $allOk = true;
     if (($this->loaded || $this->isNewRecord && $this->isNewPrepared) && $this->changedData) {
         if ($this->entityId === false) {
             throw new Exception('No entity id available for ' . __METHOD__ . '()');
         }
         if (!$this->objectId) {
             throw new Exception('No object id available for ' . __METHOD__ . '()');
         }
         $thisTime = time();
         $attributeDefs = $this->getEntityAttributeList();
         // we do not record modified, modifiedBy, created or createdBy against individual attributes but we will support
         // automatically updating them if these attributeNames have been setup as their own attributes for this entity
         if (\Yii::$app->has('user')) {
             try {
                 if (\Yii::$app->user->isGuest) {
                     $userId = 0;
                 } else {
                     $userId = \Yii::$app->user->getId();
                 }
             } catch (InvalidConfigException $e) {
                 if ($e->getMessage() == 'User::identityClass must be set.') {
                     $userId = 0;
                 } else {
                     throw $e;
                 }
             }
         }
         $extraChangeFields = array();
         if (array_key_exists('modifiedAt', $attributeDefs)) {
             if (!array_key_exists('modifiedAt', $this->changedData)) {
                 $exists = array_key_exists('modifiedAt', $this->data);
                 $this->changedData['modifiedAt'] = array_key_exists('modifiedAt', $this->data) ? $this->data['modifiedAt'] : Tools::DATE_TIME_DB_EMPTY;
                 $this->data['modifiedAt'] = date(Tools::DATETIME_DATABASE, $thisTime);
                 if ($this->lazyAttributes && array_key_exists('modifiedAt', $this->lazyAttributes)) {
                     unset($this->lazyAttributes['modifiedAt']);
                 }
             }
         }
         if (array_key_exists('modifiedBy', $attributeDefs)) {
             if (!array_key_exists('modifiedBy', $this->changedData)) {
                 if (!isset($this->data['modifiedBy']) || $this->data['modifiedBy'] != $userId) {
                     $this->changedData['modifiedBy'] = array_key_exists('modifiedBy', $this->data) ? $this->data['modifiedBy'] : 0;
                     $this->data['modifiedBy'] = $userId;
                     if ($this->lazyAttributes && array_key_exists('modifiedBy', $this->lazyAttributes)) {
                         unset($this->lazyAttributes['modifiedBy']);
                     }
                 }
             }
         }
         if (array_key_exists('createdAt', $attributeDefs)) {
             if (!array_key_exists('createdAt', $this->changedData)) {
                 $exists = array_key_exists('createdAt', $this->data);
                 if (!$exists || $exists && $this->data['createdAt'] == Tools::DATE_TIME_DB_EMPTY) {
                     $this->changedData['createdAt'] = array_key_exists('createdAt', $this->data) ? $this->data['createdAt'] : Tools::DATE_TIME_DB_EMPTY;
                     $this->data['createdAt'] = date(Tools::DATETIME_DATABASE, $thisTime);
                     if ($this->lazyAttributes && array_key_exists('created', $this->lazyAttributes)) {
                         unset($this->lazyAttributes['createdAt']);
                     }
                 }
             }
         }
         if (array_key_exists('createdBy', $attributeDefs)) {
             if (!array_key_exists('createdBy', $this->changedData)) {
                 $exists = array_key_exists('createdBy', $this->data);
                 if (!$exists || $exists && $this->data['createdBy'] != $userId) {
                     $this->changedData['createdBy'] = array_key_exists('createdBy', $this->data) ? $this->data['createdBy'] : 0;
                     $this->data['createdBy'] = $userId;
                     if ($this->lazyAttributes && array_key_exists('createdBy', $this->lazyAttributes)) {
                         unset($this->lazyAttributes['createdBy']);
                     }
                 }
             }
         }
         if (!$this->changedData) {
             $updateColumns = $this->data;
         } else {
             $updateColumns = array();
             foreach ($this->changedData as $field => $value) {
                 $updateColumns[$field] = $this->data[$field];
             }
         }
         foreach ($updateColumns as $attributeName => $attributeValue) {
             $attributeId = 0;
             $attributeDef = isset($attributeDefs[$attributeName]) ? $attributeDefs[$attributeName] : false;
             if ($attributeDef) {
                 $attributeId = $attributeDef['id'];
             }
             $ok = false;
             if ($attributeId) {
                 $attributeValue = Tools::formatAttributeValue($attributeValue, $attributeDef);
                 if ($attributeDef['deleteOnDefault'] && $attributeValue === Tools::formatAttributeValue($attributeDef['defaultValue'], $attributeDef)) {
                     // value is default so we will remove it from the attribtue table as not required
                     $ok = true;
                     if (array_key_exists($attributeName, $this->attributeValues)) {
                         $ok = $this->attributeValues[$attributeName]->deleteFull(true);
                         if ($ok) {
                             $this->setChildOldValues($attributeName, true, 'deleted');
                         } else {
                             if ($this->attributeValues[$attributeName]->hasActionErrors()) {
                                 $this->mergeActionErrors($this->attributeValues[$attributeName]->getActionErrors());
                             } else {
                                 $this->addActionError('Failed to delete attribute', 0, $attributeName);
                             }
                         }
                     }
                 } else {
                     switch (strtolower($attributeDef['dataType'])) {
                         case 'boolean':
                             $attributeValue = $attributeValue ? '1' : '0';
                             break;
                         default:
                             break;
                     }
                     if (is_null($attributeValue)) {
                         // typically where null is permitted it will be the default value with deleteOnDefault set, so should have been caught in the deleteOnDefault
                         if ($attributeDef['isNullable']) {
                             $attributeValue = '__NULL__';
                             // we do not want to allow null in the attribute database so use this string to denote null when it is permitted
                         } else {
                             $attributeValue = '__NULL__';
                             // needs to be caught elsewhere
                         }
                     }
                     if (!array_key_exists($attributeName, $this->attributeValues)) {
                         $this->attributeValues[$attributeName] = new $this->attributeValuesClass();
                         $this->attributeValues[$attributeName]->entityId = $this->entityId;
                         $this->attributeValues[$attributeName]->attributeId = $attributeId;
                         // this is a new entry that has not been included in the childHasChanges array yet
                         $this->setChildHasChanges($attributeName);
                         $this->setChildOldValues($attributeName, $this->attributeValues[$attributeName]->getResetDataForFailedSave());
                     }
                     if ($this->newObjectId) {
                         $this->attributeValues[$attributeName]->objectId = $this->newObjectId;
                     } else {
                         $this->attributeValues[$attributeName]->objectId = $this->objectId;
                     }
                     $this->attributeValues[$attributeName]->value = $attributeValue;
                     $ok = $this->attributeValues[$attributeName]->save(false, null, true, true);
                     if (!$ok) {
                         if ($this->attributeValues[$attributeName]->hasActionErrors()) {
                             $this->mergeActionErrors($this->attributeValues[$attributeName]->getActionErrors());
                         } else {
                             $this->addActionError('Failed to save attribute', 0, $attributeName);
                         }
                     }
                 }
             }
             if (!$ok) {
                 $allOk = false;
             }
         }
         if ($allOk) {
             $this->changedData = array();
             $this->loaded = true;
             $this->isNewRecord = false;
         }
     }
     if ($allOk && $this->loaded && $this->newObjectId) {
         // we need to update the objectId for all attributes belonging to
         // the current object to a new value taking into account that not
         // all attributes might have been loaded yet, if any.
         foreach ($this->attributeValues as $attributeName => $attributeValue) {
             $this->attributeValues[$attributeName]->objectId = $this->newObjectId;
             $this->attributeValues[$attributeName]->setOldAttribute('objectId', $this->newObjectId);
         }
         $attributeValuesClass = $this->attributeValuesClass;
         $ok = $attributeValuesClass::updateAll(array('objectId' => $this->newObjectId), array('objectId' => $this->objectId));
         $this->objectId = $this->newObjectId;
         $this->newObjectId = false;
     }
     return $allOk;
 }
Ejemplo n.º 2
0
 /**
  * Returns the attribute values that have been modified in this new record since loading the default values
  * Only really gets used by self::hasChanges() when _oldAttributes == [] (typically when no default values are set
  * because they are all set to null in the table schema)
  * @param string[]|null $names the names of the attributes whose values may be returned if they are
  * changed recently. If null, [[attributes()]] will be used.
  * @return array the changed attribute values (name-value pairs)
  */
 public function getIsNewDirtyAttributes($names = null)
 {
     if (!$this->getIsNewRecord() || !$this->defaultsApplied) {
         return $this->getDirtyAttributes($names);
     }
     $attributes = [];
     $theAttributes = $this->getAttributes($names);
     if ($theAttributes) {
         $stru = self::getTableSchema();
         $columns = $stru->columns;
         foreach ($theAttributes as $name => $value) {
             $spec = ArrayHelper::getValue($columns, $name, []);
             if ($spec) {
                 if ($spec->isPrimaryKey && $spec->autoIncrement) {
                     if ($value !== null) {
                         $attributes[$name] = $value;
                     }
                 } else {
                     $defaultValue = Tools::formatAttributeValue('__DEFAULT__', $spec);
                     if ($defaultValue === null && $value !== null) {
                         $attributes[$name] = $value;
                     } elseif ($defaultValue != $value) {
                         $attributes[$name] = $value;
                     }
                 }
             }
         }
     }
     return $attributes;
 }