/** * Stores the data in $obj to database. * * Note: Transaction unsafe. If you call several transaction unsafe methods * you must enclose the calls within a db transaction; thus within db->begin * and db->commit. * * @todo Change the actual access to protected instead of just marking it as such * @access protected * @param eZPersistentObject $obj * @param array|null $fieldFilters If specified only certain fields will be stored. * @return void */ public static function storeObject($obj, $fieldFilters = null) { $db = eZDB::instance(); $useFieldFilters = isset($fieldFilters) && is_array($fieldFilters) && $fieldFilters; $def = $obj->definition(); $fields = $def["fields"]; $keys = $def["keys"]; $table = $def["name"]; $relations = isset($def["relations"]) ? $def["relations"] : null; $insert_object = false; $exclude_fields = array(); foreach ($keys as $key) { $value = $obj->attribute($key); if ($value === null) { $insert_object = true; $exclude_fields[] = $key; } } if ($useFieldFilters) { $insert_object = false; } $use_fields = array_diff(array_keys($fields), $exclude_fields); // If we filter out some of the fields we need to intersect it with $use_fields if (is_array($fieldFilters)) { $use_fields = array_intersect($use_fields, $fieldFilters); } $doNotEscapeFields = array(); $changedValueFields = array(); $numericDataTypes = array('integer', 'float', 'double'); foreach ($use_fields as $field_name) { $field_def = $fields[$field_name]; $value = $obj->attribute($field_name); if ($value === null) { if (!is_array($field_def)) { $exclude_fields[] = $field_name; } else { if (array_key_exists('default', $field_def) && ($field_def['default'] !== null || $field_name == 'data_int' && array_key_exists('required', $field_def) && $field_def['required'] == false)) { $obj->setAttribute($field_name, $field_def['default']); } else { //if ( in_array( $field_def['datatype'], $numericDataTypes ) $exclude_fields[] = $field_name; } } } if (strlen($value) == 0 && is_array($field_def) && in_array($field_def['datatype'], $numericDataTypes) && array_key_exists('default', $field_def) && ($field_def['default'] === null || is_numeric($field_def['default']))) { $obj->setAttribute($field_name, $field_def['default']); } if ($value !== null && $field_def['datatype'] === 'string' && array_key_exists('max_length', $field_def) && $field_def['max_length'] > 0) { $obj->setAttribute($field_name, $db->truncateString($value, $field_def['max_length'], $field_name)); } $bindDataTypes = array('text'); if ($db->bindingType() != eZDBInterface::BINDING_NO && $db->countStringSize($value) > 2000 && is_array($field_def) && in_array($field_def['datatype'], $bindDataTypes)) { $boundValue = $db->bindVariable($value, $field_def); // $obj->setAttribute( $field_name, $value ); $doNotEscapeFields[] = $field_name; $changedValueFields[$field_name] = $boundValue; } } $key_conds = array(); foreach ($keys as $key) { $value = $obj->attribute($key); $key_conds[$key] = $value; } unset($value); $important_keys = $keys; if (is_array($relations)) { // $important_keys = array(); foreach ($relations as $relation => $relation_data) { if (!in_array($relation, $keys)) { $important_keys[] = $relation; } } } if (count($important_keys) == 0 && !$useFieldFilters) { $insert_object = true; } else { if (!$insert_object) { $rows = eZPersistentObject::fetchObjectList($def, $keys, $key_conds, array(), null, false, null, null); if (count($rows) == 0) { /* If we only want to update some fields in a record * and that records does not exist, then we should do nothing, only return. */ if ($useFieldFilters) { return; } $insert_object = true; } } } if ($insert_object) { // Note: When inserting we cannot hone the $fieldFilters parameters $use_fields = array_diff(array_keys($fields), $exclude_fields); $use_field_names = $use_fields; if ($db->useShortNames()) { $use_short_field_names = $use_field_names; eZPersistentObject::replaceFieldsWithShortNames($db, $fields, $use_short_field_names); $field_text = implode(', ', $use_short_field_names); unset($use_short_field_names); } else { $field_text = implode(', ', $use_field_names); } $use_values_hash = array(); $escapeFields = array_diff($use_fields, $doNotEscapeFields); foreach ($escapeFields as $key) { $value = $obj->attribute($key); $field_def = $fields[$key]; if ($field_def['datatype'] == 'float' || $field_def['datatype'] == 'double') { if ($value === null) { $use_values_hash[$key] = 'NULL'; } else { $use_values_hash[$key] = sprintf('%F', $value); } } else { if ($field_def['datatype'] == 'int' || $field_def['datatype'] == 'integer') { if ($value === null) { $use_values_hash[$key] = 'NULL'; } else { $use_values_hash[$key] = sprintf('%d', $value); } } else { // Note: for more colherence, we might use NULL for sql strings if the php value is NULL and not an empty sring // but to keep compatibility with ez db, where most string columns are "not null default ''", // and code feeding us a php null value without meaning it, we do not. $use_values_hash[$key] = "'" . $db->escapeString($value) . "'"; } } } foreach ($doNotEscapeFields as $key) { $use_values_hash[$key] = $changedValueFields[$key]; } $use_values = array(); foreach ($use_field_names as $field) { $use_values[] = $use_values_hash[$field]; } unset($use_values_hash); $value_text = implode(", ", $use_values); $sql = "INSERT INTO {$table} ({$field_text}) VALUES({$value_text})"; $db->query($sql); if (isset($def["increment_key"]) && is_string($def["increment_key"]) && !($obj->attribute($def["increment_key"]) > 0)) { $inc = $def["increment_key"]; $id = $db->lastSerialID($table, $inc); if ($id !== false) { $obj->setAttribute($inc, $id); } } } else { $use_fields = array_diff(array_keys($fields), array_merge($keys, $exclude_fields)); if (count($use_fields) > 0) { // If we filter out some of the fields we need to intersect it with $use_fields if (is_array($fieldFilters)) { $use_fields = array_intersect($use_fields, $fieldFilters); } $use_field_names = array(); foreach ($use_fields as $key) { if ($db->useShortNames() && is_array($fields[$key]) && array_key_exists('short_name', $fields[$key]) && strlen($fields[$key]['short_name']) > 0) { $use_field_names[$key] = $fields[$key]['short_name']; } else { $use_field_names[$key] = $key; } } $field_text = ""; $field_text_len = 0; $i = 0; foreach ($use_fields as $key) { $value = $obj->attribute($key); if ($fields[$key]['datatype'] == 'float' || $fields[$key]['datatype'] == 'double') { if ($value === null) { $field_text_entry = $use_field_names[$key] . '=NULL'; } else { $field_text_entry = $use_field_names[$key] . "=" . sprintf('%F', $value); } } else { if ($fields[$key]['datatype'] == 'int' || $fields[$key]['datatype'] == 'integer') { if ($value === null) { $field_text_entry = $use_field_names[$key] . '=NULL'; } else { $field_text_entry = $use_field_names[$key] . "=" . sprintf('%d', $value); } } else { if (in_array($use_field_names[$key], $doNotEscapeFields)) { $field_text_entry = $use_field_names[$key] . "=" . $changedValueFields[$key]; } else { $field_text_entry = $use_field_names[$key] . "='" . $db->escapeString($value) . "'"; } } } $field_text_len += strlen($field_text_entry); $needNewline = false; if ($field_text_len > 60) { $needNewline = true; $field_text_len = 0; } if ($i > 0) { $field_text .= "," . ($needNewline ? "\n " : ' '); } $field_text .= $field_text_entry; ++$i; } $cond_text = eZPersistentObject::conditionText($key_conds); $sql = "UPDATE {$table} SET {$field_text}{$cond_text}"; $db->query($sql); } } $obj->setHasDirtyData(false); }