/**
  * Returns an order value which can be used for new items in table,
  * for instance placement.
  *
  * Uses $def, $orderField and $conditions to figure out the currently maximum
  * order value and returns one that is larger.
  *
  * @param array $def A definition array of all fields, table name and sorting (see {@link eZPersistentObject::definition()} for more info)
  * @param string $orderField
  * @param array $conditions
  * @return int
  */
 public static function newObjectOrder($def, $orderField, $conditions)
 {
     $db = eZDB::instance();
     $table = $def["name"];
     $keys = $def["keys"];
     $cond_text = eZPersistentObject::conditionText($conditions);
     $rows = $db->arrayQuery("SELECT MAX({$orderField}) AS {$orderField} FROM {$table} {$cond_text}");
     if (count($rows) > 0 and isset($rows[0][$orderField])) {
         return $rows[0][$orderField] + 1;
     } else {
         return 1;
     }
 }
 /**
  *  Stores the data in \a $obj to database.
  *
  *  a little modification - stores tehe placeholdervalues for the virtual list so we now if we should get
  *  a value from parent list
  *
  *  fieldFilters If specified only certain fields will be stored.
  * \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.
  *
  * @param unknown_type $obj
  * @param unknown_type $fieldFilters
  * @see eZPersistentObject::storeObject
  */
 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 );
         $value = $obj->attributeContentToStore($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 );
         $value = $obj->attributeContentToStore($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 && strlen($value) > $field_def['max_length']) {
             $obj->setAttribute($field_name, substr($value, 0, $field_def['max_length']));
             eZDebug::writeDebug($value, "truncation of {$field_name} to max_length=" . $field_def['max_length']);
         }
         $bindDataTypes = array('text');
         if ($db->bindingType() != eZDBInterface::BINDING_NO && strlen($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 );
         $value = $obj->attributeContentToStore($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 );
             $value = $obj->attributeContentToStore($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->attributeContentToStore($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 );
                 $value = $obj->attributeContentToStore($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);
 }
 static function newObjectOrder( $def, $orderField, $conditions )
 {
     $db = eZDB::instance();
     $table = $def["name"];
     $keys = $def["keys"];
     $cond_text = eZPersistentObject::conditionText( $conditions );
     $rows = $db->arrayQuery( "SELECT MAX($orderField) AS $orderField FROM $table $cond_text" );
     if ( count( $rows ) > 0 and isset( $rows[0][$orderField] ) )
         return $rows[0][$orderField] + 1;
     else
         return 1;
 }