- Модуль: tasks
- Путь к файлу: ~/bitrix/modules/tasks/lib/item.php
- Класс: BitrixTasksItem
- Вызов: Item::save
public function save($settings = array())
{
$dc = static::getDataSourceClass();
if($this->isImmutable())
{
$result = new Result();
$result->getErrors()->add('IS_IMMUTABLE', 'Item is read-only');
return $result;
}
$state = $this->getTransitionState();
if($state->isInProgress())
{
$result = new Result();
$result->getErrors()->add('IN_TRANSITION', 'Item is in transition state, no overlapping operations available');
return $result;
}
$map = $this->getMap();
$ufc = $this->getUserFieldController();
$accessResult = new Result();
// first - check access
if($this->id) // we want update
{
$canPerform = $this->canUpdate($accessResult);
}
else
{
$canPerform = $this->canCreate($accessResult);
}
if($canPerform)
{
$state->enter(
array(),
$this->id ? State::MODE_UPDATE : State::MODE_CREATE
);
/** @var Result $result */
$result = $state->getResult();
/** @var FieldScalar $field */
foreach($map as $field)
{
$name = $field->getName();
if(!$this->isFieldModified($name))
{
// assign default values here, like they were modified...
if(!$this->id && $field->hasDefaultValue($name, $this))
{
$field->setValue($field->getDefaultValue($name, $this), $name, $this);
$this->setFieldModified($name); // mark as modified, to be saved
continue;
}
}
}
// if we can, then run deep into structure and prepare data
$this->prepareData($result);
// todo: onBeforeSave event here
// after that, run deep one more time and check data before saving
$this->checkData($result);
if($result->isSuccess() && $this->doPreActions($state) && $this->executeHooksBefore($state))
{
$tablet = array();
$extra = array();
/** @var ItemFieldScalar $field */
foreach($map as $field)
{
$name = $field->getName();
// skip non-writable fields
// skip unchanged fields
// skip non-cache-able fields that can NOT be written to the database
if(!$field->isDBWritable() || !($this->isFieldModified($name) || (!$field->isCacheable() && $field->isDBWritable())))
{
continue;
}
$dbName = $field->getDBName();
$value = $this[$name];
$isTablet = $field->isSourceTablet();
$isUf = $ufc && $field->isSourceUserField();
$isCustom = $field->isSourceCustom();
if ($value !== null)
{
if ($isTablet || $isUf)
{
$tablet[$dbName] = $field->translateValueToDatabase($value, $name, $this);
}
elseif ($isCustom)
{
$extra[$name] = $value; // the field will save data by itself
}
}
}
$tablet = $this->modifyTabletDataBeforeSave($tablet);
$authContext = new BitrixMainAuthenticationContext();
$authContext->setUserId($this->getUserId());
unset($tablet['ID']);
$tablet = array("fields" => $tablet, "auth_context" => $authContext);
if($this->id)
{
$dbResult = $dc::update($this->id, $tablet);
}
else
{
$dbResult = $dc::add($tablet);
}
if($dbResult->isSuccess())
{
if(!$this->id)
{
$this->setId($dbResult->getId()); // bind current instance to the newly created item
}
// now save each extra field separately
// todo: not only custom fields could have saveValueToDataBase() implemented!!!
// todo: for example, task`s PARENT_ID can create additional structures with saveValueToDataBase()
foreach($extra as $k => $v)
{
/** @var FieldScalar $fld */
$fld = $map[$k];
$subSaveResult = $fld->saveValueToDataBase($v, $k, $this);
$result->adoptErrors($subSaveResult, array(
'CODE' => $k.'.#CODE#',
'MESSAGE' => Loc::getMessage('TASKS_ITEM_SUBITEM_SAVE_ERROR', array(
'#ENTITY_NAME#' => $fld->getTitle()
)).': #MESSAGE#',
));
}
$this->executeHooksAfter($state);
$this->doPostActions($state);
// todo: onAfterSave event here
}
else
{
$result->adoptErrors($dbResult);
}
}
$result->setInstance($this);
$state->leave();
}
else
{
$result = new Result();
}
$result->adoptErrors($accessResult);
if(
$result->isSuccess()
&&
(
!isset($settings['KEEP_DATA'])
|| $settings['KEEP_DATA'] !== true
)
)
{
$this->clearData();
}
return $result;
}