/** * Save changes to database, it's an good idea to use save() instead * * @return void */ public function update() { parent::update(); // get fields which shouldn't be updated $fieldDefinitions = $this->model->getClass()->getFieldDefinitions(); $untouchable = []; foreach ($fieldDefinitions as $key => $fd) { if (method_exists($fd, "getLazyLoading") && $fd->getLazyLoading()) { if (!in_array($key, $this->model->getLazyLoadedFields())) { //this is a relation subject to lazy loading - it has not been loaded $untouchable[] = $key; } } } // empty relation table except the untouchable fields (eg. lazy loading fields) if (count($untouchable) > 0) { $untouchables = "'" . implode("','", $untouchable) . "'"; $this->db->delete("object_relations_" . $this->model->getClassId(), $this->db->quoteInto("src_id = ? AND fieldname not in (" . $untouchables . ") AND ownertype = 'object'", $this->model->getId())); } else { $this->db->delete("object_relations_" . $this->model->getClassId(), $this->db->quoteInto("src_id = ? AND ownertype = 'object'", $this->model->getId())); } $inheritedValues = Object\AbstractObject::doGetInheritedValues(); Object\AbstractObject::setGetInheritedValues(false); $data = []; $data["oo_id"] = $this->model->getId(); foreach ($fieldDefinitions as $key => $fd) { $getter = "get" . ucfirst($key); if (method_exists($fd, "save")) { // for fieldtypes which have their own save algorithm eg. fieldcollections, objects, multihref, ... $fd->save($this->model); } elseif ($fd->getColumnType()) { // pimcore saves the values with getDataForResource if (is_array($fd->getColumnType())) { $insertDataArray = $fd->getDataForResource($this->model->{$getter}(), $this->model); if (is_array($insertDataArray)) { $data = array_merge($data, $insertDataArray); } } else { $insertData = $fd->getDataForResource($this->model->{$getter}(), $this->model); $data[$key] = $insertData; } } } $this->db->insertOrUpdate("object_store_" . $this->model->getClassId(), $data); // get data for query table $data = []; $this->inheritanceHelper->resetFieldsToCheck(); $oldData = $this->db->fetchRow("SELECT * FROM object_query_" . $this->model->getClassId() . " WHERE oo_id = ?", $this->model->getId()); $inheritanceEnabled = $this->model->getClass()->getAllowInherit(); $parentData = null; if ($inheritanceEnabled) { // get the next suitable parent for inheritance $parentForInheritance = $this->model->getNextParentForInheritance(); if ($parentForInheritance) { // we don't use the getter (built in functionality to get inherited values) because we need to avoid race conditions // we cannot Object\AbstractObject::setGetInheritedValues(true); and then $this->model->$method(); // so we select the data from the parent object using FOR UPDATE, which causes a lock on this row // so the data of the parent cannot be changed while this transaction is on progress $parentData = $this->db->fetchRow("SELECT * FROM object_query_" . $this->model->getClassId() . " WHERE oo_id = ? FOR UPDATE", $parentForInheritance->getId()); } } foreach ($fieldDefinitions as $key => $fd) { if ($fd->getQueryColumnType()) { //exclude untouchables if value is not an array - this means data has not been loaded if (!(in_array($key, $untouchable) and !is_array($this->model->{$key}))) { $method = "get" . $key; $fieldValue = $this->model->{$method}(); $insertData = $fd->getDataForQueryResource($fieldValue, $this->model); $isEmpty = $fd->isEmpty($fieldValue); if (is_array($insertData)) { $columnNames = array_keys($insertData); $data = array_merge($data, $insertData); } else { $columnNames = [$key]; $data[$key] = $insertData; } // if the current value is empty and we have data from the parent, we just use it if ($isEmpty && $parentData) { foreach ($columnNames as $columnName) { if (array_key_exists($columnName, $parentData)) { $data[$columnName] = $parentData[$columnName]; if (is_array($insertData)) { $insertData[$columnName] = $parentData[$columnName]; } else { $insertData = $parentData[$columnName]; } } } } if ($inheritanceEnabled && $fd->getFieldType() != "calculatedValue") { //get changed fields for inheritance if ($fd->isRelationType()) { if (is_array($insertData)) { $doInsert = false; foreach ($insertData as $insertDataKey => $insertDataValue) { if ($isEmpty && $oldData[$insertDataKey] == $parentData[$insertDataKey]) { // do nothing, ... value is still empty and parent data is equal to current data in query table } elseif ($oldData[$insertDataKey] != $insertDataValue) { $doInsert = true; break; } } if ($doInsert) { $this->inheritanceHelper->addRelationToCheck($key, $fd, array_keys($insertData)); } } else { if ($isEmpty && $oldData[$key] == $parentData[$key]) { // do nothing, ... value is still empty and parent data is equal to current data in query table } elseif ($oldData[$key] != $insertData) { $this->inheritanceHelper->addRelationToCheck($key, $fd); } } } else { if (is_array($insertData)) { foreach ($insertData as $insertDataKey => $insertDataValue) { if ($isEmpty && $oldData[$insertDataKey] == $parentData[$insertDataKey]) { // do nothing, ... value is still empty and parent data is equal to current data in query table } elseif ($oldData[$insertDataKey] != $insertDataValue) { $this->inheritanceHelper->addFieldToCheck($insertDataKey, $fd); } } } else { if ($isEmpty && $oldData[$key] == $parentData[$key]) { // do nothing, ... value is still empty and parent data is equal to current data in query table } elseif ($oldData[$key] != $insertData) { // data changed, do check and update $this->inheritanceHelper->addFieldToCheck($key, $fd); } } } } } else { Logger::debug("Excluding untouchable query value for object [ " . $this->model->getId() . " ] key [ {$key} ] because it has not been loaded"); } } } $data["oo_id"] = $this->model->getId(); $this->db->insertOrUpdate("object_query_" . $this->model->getClassId(), $data); Object\AbstractObject::setGetInheritedValues($inheritedValues); }