/** * Saves an Object. * * @param GenericORMapperDataObject $object the object to save. * * @return int Database id of the object. * @throws GenericORMapperException In case the object name cannot be found within the mapping table. * * @author Christian Achatz * @version * Version 0.1, 11.05.2008<br /> * Version 0.2, 26.10.2008 (Added a check, if the desired object name exists in the mapping table.)<br /> * Version 0.3, 27.12.2008 (Update is now done, if params are located in the params array)<br /> * Version 0.4, 02.01.2010 (Added ticks for property names to avoid key word issues)<br /> * Version 0.5, 08.01.2010 (Added property value escaping in order to avoid sql injections)<br /> * Version 0.6, 15.01.2011 (Added event handler calls)<br /> * Version 0.7, 15.02.2011 (Moved eventhandler calls to GORM-function, because afterSave() was called before whole tree was saved)<br /> */ public function saveObject(GenericORMapperDataObject &$object) { // get information about object to load $objectName = $object->getObjectName(); if (!isset($this->mappingTable[$objectName])) { throw new GenericORMapperException('[GenericORMapper::saveObject()] The object name "' . $objectName . '" does not exist in the mapping table! Hence, your object cannot be saved! ' . 'Please check your object configuration.', E_USER_ERROR); } $pkName = $this->mappingTable[$objectName]['ID']; $attrExceptions = [$pkName, 'ModificationTimestamp', 'CreationTimestamp']; // check if object must be saved or updated $id = $object->getProperty($pkName); if ($id === null) { // do an INSERT $insert = 'INSERT INTO ' . $this->mappingTable[$objectName]['Table']; $names = []; $values = []; foreach ($object->getProperties() as $propertyName => $propertyValue) { if (!in_array($propertyName, $attrExceptions)) { // Surround property names with ticks to avoid issues with reserved names! $names[] = '`' . $propertyName . '`'; // escape value to avoid SQL injections $propertyValue = $this->dbDriver->escapeValue($propertyValue); // Check, whether the desired property is a BIT field. If yes, prepend with // the binary marker! Details can be read about under // http://forum.adventure-php-framework.org/viewtopic.php?f=8&t=234. if (stripos($this->mappingTable[$objectName][$propertyName], self::$BIT_FIELD_IDENTIFIER) === false) { // check, whether the field is a null value and translate PHP null values into // MySQL NULL value if (stripos($this->mappingTable[$objectName][$propertyName], self::$NULL_FIELD_IDENTIFIER) === false) { $values[] = '\'' . $propertyValue . '\''; } else { if (empty($propertyValue)) { $values[] = 'NULL'; } else { $values[] = '\'' . $propertyValue . '\''; } } } else { $values[] = 'b\'' . $propertyValue . '\''; } } } $insert .= ' (' . implode(', ', $names) . ')'; $insert .= ' VALUES (' . implode(', ', $values) . ');'; $this->dbDriver->executeTextStatement($insert, $this->logStatements); $id = $this->dbDriver->getLastID(); } else { // UPDATE object in database $update = 'UPDATE ' . $this->mappingTable[$objectName]['Table']; $queryParams = []; foreach ($object->getProperties() as $propertyName => $propertyValue) { if (!in_array($propertyName, $attrExceptions)) { // escape value to avoid SQL injections $propertyValue = $this->dbDriver->escapeValue($propertyValue); // Check, whether the desired property is a BIT field. If yes, prepend with // the binary marker! Details can be read about under // http://forum.adventure-php-framework.org/viewtopic.php?f=8&t=234. if (stripos($this->mappingTable[$objectName][$propertyName], self::$BIT_FIELD_IDENTIFIER) === false) { // check, whether the field is a null value and translate PHP null values into // MySQL NULL value if (stripos($this->mappingTable[$objectName][$propertyName], self::$NULL_FIELD_IDENTIFIER) === false) { $value = '\'' . $propertyValue . '\''; } else { if (empty($propertyValue)) { $value = 'NULL'; } else { $value = '\'' . $propertyValue . '\''; } } $queryParams[] = '`' . $propertyName . '` = ' . $value; } else { $queryParams[] = '`' . $propertyName . '` = b\'' . $propertyValue . '\''; } } } $update .= ' SET ' . implode(', ', $queryParams) . ', ModificationTimestamp = NOW()'; $update .= ' WHERE ' . $pkName . '= \'' . $id . '\';'; // execute update, only if the update is necessary if (count($queryParams) > 0) { $this->dbDriver->executeTextStatement($update, $this->logStatements); } } // initialize the object id, to enable the developer to directly // reuse the object after saving it. (added for release 1.11) $object->setProperty($pkName, $id); // inject data component to be able to reuse the saved object loading // related object or create associations. (added for release 1.11) $object->setDataComponent($this); // return the database ID of the object for further usage return $id; }