/** * Обновление модели на основе данных, пришедших из json-контроллера * * @param $jsonString * @return array */ public function updateWithJsonString($jsonString) { // данные модели $modelData = json_decode($jsonString, true); // убираем служебную инфу if (array_key_exists("_translation", $modelData)) { unset($modelData["_translation"]); } // попробуем сохранить данные, которые находятся в отношениях // многие-ко-многим foreach ($this->relations() as $field => $properties) { if ($properties["relationPower"] == RELATION_MANY_TO_MANY) { if (array_key_exists($field, $modelData)) { $data = $modelData[$field]; // уберем их из модели unset($modelData[$field]); // уберем уже имеющиеся данные из связанной таблицы /** * @var CActiveRecord $ar */ if (array_key_exists("id", $modelData)) { foreach (CActiveRecordProvider::getWithCondition($properties["joinTable"], trim(CUtils::strLeft($properties["leftCondition"], "=")) . "=" . $modelData["id"])->getItems() as $ar) { $ar->remove(); } } // добавим туда новые данные foreach ($data as $value) { $ar = new CActiveRecord(array($properties["rightKey"] => $value["id"], trim(CUtils::strLeft($properties["leftCondition"], "=")) => $modelData["id"], "id" => null)); $ar->setTable($properties["joinTable"]); $ar->insert(); } } } elseif ($properties["relationPower"] == RELATION_HAS_MANY) { if (array_key_exists($field, $modelData)) { $data = $modelData[$field]; // уберем данные из модели unset($modelData[$field]); // если в свойствах отношения указан целевой класс, то // будем обновлять автоматом if (array_key_exists("targetClass", $properties)) { // получим список записей, которые уже есть $targetClass = $properties["targetClass"]; /** * @var CActiveModel $targetObj */ $targetObj = new $targetClass(); $docsToRemove = array(); // его может не быть, если запись новая if (array_key_exists("id", $modelData)) { $items = CActiveRecordProvider::getWithCondition($targetObj->getTable(), trim(CUtils::strLeft($properties["storageCondition"], "=")) . "=" . $modelData["id"]); /** * @var CActiveRecord $item */ foreach ($items->getItems() as $item) { $docsToRemove[] = $item->getId(); } } /** * @var string $item */ foreach ($data as $item) { // полученные данные обратно в json, чтобы // можно было все сделать одинаково рекурсивно $childJsonData = json_encode($item); // создадим экземпляр целевого класса /** * @var CActiveModel $targetObj */ $targetObj = new $targetClass(); $targetObj->updateWithJsonString($childJsonData); $targetObj->save(); // уберем из списка добавленную запись if (in_array($targetObj->getId(), $docsToRemove)) { unset($docsToRemove[array_search($targetObj->getId(), $docsToRemove)]); } } // удалим элементы из списка на удаление - мы // их удалили и вместе с другими данными с клиента // они не пришли if (count($docsToRemove) > 0) { CActiveRecordProvider::removeWithCondition($targetObj->getTable(), "id in (" . implode(", ", $docsToRemove) . ")"); } } } } } // данные обратно в модель foreach ($modelData as $key => $value) { $this->{$key} = $value; } return $modelData; }