|
eZ Publish
[trunk]
|
00001 <?php 00002 /** 00003 * File containing the eZPersistentObject class. 00004 * 00005 * @copyright Copyright (C) 1999-2012 eZ Systems AS. All rights reserved. 00006 * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2 00007 * @version //autogentag// 00008 * @package kernel 00009 */ 00010 00011 /** 00012 * Allows for object persistence in a database 00013 * 00014 * Classes which stores simple types in databases should inherit from this 00015 * and implement the definition() function. The class will then get initialization, 00016 * fetching, listing, moving, storing and deleting for free as well as attribute 00017 * access. The new class must have a constructor which takes one parameter called 00018 * $row and pass that this constructor. 00019 * 00020 * <code> 00021 * class MyClass extends eZPersistentObject 00022 * { 00023 * public function __construct( $row ) 00024 * { 00025 * parent::__construct( $row ); 00026 * } 00027 * } 00028 * </code> 00029 * 00030 * @package eZKernel 00031 * @method fetch 00032 */ 00033 class eZPersistentObject 00034 { 00035 /** 00036 * Whether the data is dirty, ie needs to be stored, or not. 00037 * 00038 * @todo Change the actual access to protected instead of just marking it as such 00039 * @access protected 00040 * @var bool 00041 */ 00042 public $PersistentDataDirty; 00043 00044 /** 00045 * Initializes the object with the $row. 00046 * 00047 * It will try to set each field taken from the database row. Calls fill 00048 * to do the job. If $row is an integer, it will try to fetch it from the 00049 * database using it as the unique ID. 00050 * 00051 * @param int|array $row 00052 */ 00053 public function eZPersistentObject( $row ) 00054 { 00055 $this->PersistentDataDirty = false; 00056 if ( is_numeric( $row ) ) 00057 $row = $this->fetch( $row, false ); 00058 $this->fill( $row ); 00059 } 00060 00061 /** 00062 * Tries to fill in the data in the object by using the object definition 00063 * which is returned by the function definition() and the database row 00064 * data $row. Each field will be fetch from the definition and then 00065 * use that fieldname to fetch from the row and set the data. 00066 * 00067 * @todo Change the actual access to protected instead of just marking it as such 00068 * @access protected 00069 * @param array $row 00070 * @return bool 00071 */ 00072 public function fill( $row ) 00073 { 00074 if ( !is_array( $row ) ) 00075 return; 00076 $def = $this->definition(); 00077 00078 foreach ( $def["fields"] as $key => $item ) 00079 { 00080 if ( isset( $item['name'] ) ) 00081 { 00082 $item = $item['name']; 00083 } 00084 $this->$item = isset( $row[$key] ) ? $row[$key] : null; 00085 } 00086 00087 return true; 00088 } 00089 00090 /** 00091 * For the given array $fields treats its keys (for associative array) or 00092 * values (for non-associative array) as table fields names and replaces them 00093 * with short names (aliases) found in $fieldDefs. 00094 * 00095 * @todo Change the actual access to protected instead of just marking it as such 00096 * @access protected 00097 * @param eZDBInterface $db 00098 * @param array $fieldDefs 00099 * @param array $fields 00100 * @return void 00101 */ 00102 public static function replaceFieldsWithShortNames( $db, $fieldDefs, &$fields ) 00103 { 00104 if ( !$db->useShortNames() || !$fields ) 00105 return; 00106 00107 $short_fields_names = array(); 00108 foreach ( $fields as $key => $val ) 00109 { 00110 if( is_numeric( $key ) ) // $fields is not an associative array 00111 { 00112 if ( array_key_exists( $val, $fieldDefs ) && 00113 array_key_exists( 'short_name', $fieldDefs[$val] ) ) 00114 { 00115 $short_fields_names[$key] = $fieldDefs[$val]['short_name']; 00116 } 00117 else 00118 $short_fields_names[$key] = $val; 00119 } 00120 else // $fields is an associative array 00121 { 00122 if ( array_key_exists( $key, $fieldDefs ) && 00123 array_key_exists( 'short_name', $fieldDefs[$key] ) ) 00124 { 00125 $newkey = $fieldDefs[$key]['short_name']; 00126 } 00127 else 00128 $newkey = $key; 00129 $short_fields_names[$newkey] = $val; 00130 } 00131 00132 } 00133 $fields = $short_fields_names; 00134 } 00135 00136 /** 00137 * Fetches the number of rows by using the object definition. 00138 * 00139 * Uses fetchObjectList for the actual SQL handling. 00140 * See {@link eZPersistentObject::fetchObjectList()} for a full description 00141 * of the input parameters. 00142 * 00143 * @param array $def A definition array of all fields, table name and sorting (see {@link eZPersistentObject::definition()} for more info) 00144 * @param array|null $conds 00145 * @param string|null $field 00146 * @return int 00147 */ 00148 public static function count( $def, $conds = null, $field = null ) 00149 { 00150 if ( !isset( $field ) ) 00151 { 00152 $field = '*'; 00153 } 00154 $customFields = array( array( 'operation' => 'COUNT( ' . $field . ' )', 'name' => 'row_count' ) ); 00155 $rows = eZPersistentObject::fetchObjectList( $def, array(), $conds, array(), null, false, false, $customFields ); 00156 return $rows[0]['row_count']; 00157 } 00158 00159 /** 00160 * Fetches and returns an object based on the given parameters and returns 00161 * is either as an object or as an array 00162 * 00163 * See {@link eZPersistentObject::fetchObjectList()} for a full description 00164 * of the input parameters. 00165 * 00166 * @param array $def A definition array of all fields, table name and sorting (see {@link eZPersistentObject::definition()} for more info) 00167 * @param array $field_filters If defined determines the fields which are extracted, if not all fields are fetched 00168 * @param array $conds An array of conditions which determines which rows are fetched 00169 * @param bool $asObject If true the returned item is an object otherwise a db row (array). 00170 * @param array|null $grouping An array of elements to group by 00171 * @param array $custom_fields|null An array of extra fields to fetch, each field may be a SQL operation 00172 * @return eZPersistentObject|array|null 00173 */ 00174 public static function fetchObject( $def, $field_filters, $conds, $asObject = true, $grouping = null, $custom_fields = null ) 00175 { 00176 $rows = eZPersistentObject::fetchObjectList( $def, $field_filters, $conds, 00177 array(), null, $asObject, 00178 $grouping, $custom_fields ); 00179 if ( $rows ) 00180 return $rows[0]; 00181 return null; 00182 } 00183 00184 /** 00185 * Removes the object from the database, it will use the keys in the object 00186 * definition to figure out which table row should be removed unless 00187 * $conditions is defined as an array with fieldnames. 00188 * 00189 * It uses removeObject to do the real job and passes the object defintion, 00190 * conditions and extra conditions \a $extraConditions to this function. 00191 * 00192 * Note: Transaction unsafe. If you call several transaction unsafe methods 00193 * you must enclose the calls within a db transaction; thus within db->begin 00194 * and db->commit. 00195 * 00196 * @param array|null $conditions 00197 * @param array|null $extraConditions 00198 * @return void 00199 */ 00200 public function remove( $conditions = null, $extraConditions = null ) 00201 { 00202 $def = $this->definition(); 00203 $keys = $def["keys"]; 00204 if ( !is_array( $conditions ) ) 00205 { 00206 $conditions = array(); 00207 foreach ( $keys as $key ) 00208 { 00209 $value = $this->attribute( $key ); 00210 $conditions[$key] = $value; 00211 } 00212 } 00213 eZPersistentObject::removeObject( $def, $conditions, $extraConditions ); 00214 } 00215 00216 /** 00217 * Deletes the object from the table defined in $def with conditions $conditions 00218 * and extra conditions \a $extraConditions. The extra conditions will either be 00219 * appended to the existing conditions or overwrite existing fields. 00220 * 00221 * Uses conditionText() to create the condition SQL. 00222 * 00223 * Note: Transaction unsafe. If you call several transaction unsafe methods 00224 * you must enclose the calls within a db transaction; thus within db->begin 00225 * and db->commit. 00226 * 00227 * @param array $def A definition array of all fields, table name and sorting (see {@link eZPersistentObject::definition()} for more info) 00228 * @param array|null $conditions 00229 * @param array|null $extraConditions 00230 * @return void 00231 */ 00232 public static function removeObject( $def, $conditions = null, $extraConditions = null ) 00233 { 00234 $db = eZDB::instance(); 00235 00236 $table = $def["name"]; 00237 if ( is_array( $extraConditions ) ) 00238 { 00239 foreach ( $extraConditions as $key => $cond ) 00240 { 00241 $conditions[$key] = $cond; 00242 } 00243 } 00244 00245 // substitute fields mentioned the conditions whith their short names (if any) 00246 $fields = $def['fields']; 00247 eZPersistentObject::replaceFieldsWithShortNames( $db, $fields, $conditions ); 00248 00249 $cond_text = eZPersistentObject::conditionText( $conditions ); 00250 00251 $db->query( "DELETE FROM $table $cond_text" ); 00252 } 00253 00254 /** 00255 * Stores the object in the database, uses storeObject() to do the actual 00256 * job and passes $fieldFilters to it. 00257 * 00258 * Note: Transaction unsafe. If you call several transaction unsafe methods 00259 * you must enclose the calls within a db transaction; thus within db->begin 00260 * and db->commit. 00261 * 00262 * @param array|null $fieldFilters 00263 * @return void 00264 */ 00265 public function store( $fieldFilters = null ) 00266 { 00267 eZPersistentObject::storeObject( $this, $fieldFilters ); 00268 } 00269 00270 /** 00271 * Makes sure data is stored if the data is considered dirty. 00272 * 00273 * Note: Transaction unsafe. If you call several transaction unsafe methods 00274 * you must enclose the calls within a db transaction; thus within db->begin 00275 * and db->commit. 00276 * 00277 * @param array|null $fieldFilters 00278 * @return void 00279 */ 00280 public function sync( $fieldFilters = null ) 00281 { 00282 if ( $this->hasDirtyData() ) 00283 $this->store( $fieldFilters ); 00284 } 00285 00286 /** 00287 * Stores the data in $obj to database. 00288 * 00289 * Note: Transaction unsafe. If you call several transaction unsafe methods 00290 * you must enclose the calls within a db transaction; thus within db->begin 00291 * and db->commit. 00292 * 00293 * @todo Change the actual access to protected instead of just marking it as such 00294 * @access protected 00295 * @param eZPersistentObject $obj 00296 * @param array|null $fieldFilters If specified only certain fields will be stored. 00297 * @return void 00298 */ 00299 public static function storeObject( $obj, $fieldFilters = null ) 00300 { 00301 $db = eZDB::instance(); 00302 $useFieldFilters = ( isset( $fieldFilters ) && is_array( $fieldFilters ) && $fieldFilters ); 00303 00304 $def = $obj->definition(); 00305 $fields = $def["fields"]; 00306 $keys = $def["keys"]; 00307 $table = $def["name"]; 00308 $relations = isset( $def["relations"] ) ? $def["relations"] : null; 00309 $insert_object = false; 00310 $exclude_fields = array(); 00311 foreach ( $keys as $key ) 00312 { 00313 $value = $obj->attribute( $key ); 00314 if ( $value === null ) 00315 { 00316 $insert_object = true; 00317 $exclude_fields[] = $key; 00318 } 00319 } 00320 00321 if ( $useFieldFilters ) 00322 $insert_object = false; 00323 00324 $use_fields = array_diff( array_keys( $fields ), $exclude_fields ); 00325 // If we filter out some of the fields we need to intersect it with $use_fields 00326 if ( is_array( $fieldFilters ) ) 00327 $use_fields = array_intersect( $use_fields, $fieldFilters ); 00328 $doNotEscapeFields = array(); 00329 $changedValueFields = array(); 00330 $numericDataTypes = array( 'integer', 'float', 'double' ); 00331 00332 foreach ( $use_fields as $field_name ) 00333 { 00334 $field_def = $fields[$field_name]; 00335 $value = $obj->attribute( $field_name ); 00336 00337 if ( $value === null ) 00338 { 00339 if ( ! is_array( $field_def ) ) 00340 { 00341 $exclude_fields[] = $field_name; 00342 } 00343 else 00344 { 00345 if ( array_key_exists( 'default', $field_def ) && 00346 ( $field_def['default'] !== null || 00347 ( $field_name == 'data_int' && 00348 array_key_exists( 'required', $field_def ) && 00349 $field_def[ 'required' ] == false ) ) ) 00350 { 00351 $obj->setAttribute( $field_name, $field_def[ 'default' ] ); 00352 } 00353 else 00354 { 00355 //if ( in_array( $field_def['datatype'], $numericDataTypes ) 00356 $exclude_fields[] = $field_name; 00357 } 00358 } 00359 } 00360 00361 if ( strlen( $value ) == 0 && 00362 is_array( $field_def ) && 00363 in_array( $field_def['datatype'], $numericDataTypes ) && 00364 array_key_exists( 'default', $field_def ) && 00365 ( $field_def[ 'default' ] === null || is_numeric( $field_def[ 'default' ] ) ) ) 00366 { 00367 $obj->setAttribute( $field_name, $field_def[ 'default' ] ); 00368 } 00369 00370 if ( $value !== null && 00371 $field_def['datatype'] === 'string' && 00372 array_key_exists( 'max_length', $field_def ) && 00373 $field_def['max_length'] > 0 && 00374 strlen( $value ) > $field_def['max_length'] ) 00375 { 00376 $obj->setAttribute( $field_name, substr( $value, 0, $field_def['max_length'] ) ); 00377 eZDebug::writeDebug( $value, "truncation of $field_name to max_length=". $field_def['max_length'] ); 00378 } 00379 $bindDataTypes = array( 'text' ); 00380 if ( $db->bindingType() != eZDBInterface::BINDING_NO && 00381 strlen( $value ) > 2000 && 00382 is_array( $field_def ) && 00383 in_array( $field_def['datatype'], $bindDataTypes ) 00384 ) 00385 { 00386 $boundValue = $db->bindVariable( $value, $field_def ); 00387 // $obj->setAttribute( $field_name, $value ); 00388 $doNotEscapeFields[] = $field_name; 00389 $changedValueFields[$field_name] = $boundValue; 00390 } 00391 00392 } 00393 $key_conds = array(); 00394 foreach ( $keys as $key ) 00395 { 00396 $value = $obj->attribute( $key ); 00397 $key_conds[$key] = $value; 00398 } 00399 unset( $value ); 00400 00401 $important_keys = $keys; 00402 if ( is_array( $relations ) ) 00403 { 00404 // $important_keys = array(); 00405 foreach( $relations as $relation => $relation_data ) 00406 { 00407 if ( !in_array( $relation, $keys ) ) 00408 $important_keys[] = $relation; 00409 } 00410 } 00411 if ( count( $important_keys ) == 0 && !$useFieldFilters ) 00412 { 00413 $insert_object = true; 00414 } 00415 else if ( !$insert_object ) 00416 { 00417 $rows = eZPersistentObject::fetchObjectList( $def, $keys, $key_conds, 00418 array(), null, false, 00419 null, null ); 00420 if ( count( $rows ) == 0 ) 00421 { 00422 /* If we only want to update some fields in a record 00423 * and that records does not exist, then we should do nothing, only return. 00424 */ 00425 if ( $useFieldFilters ) 00426 return; 00427 00428 $insert_object = true; 00429 } 00430 } 00431 00432 if ( $insert_object ) 00433 { 00434 // Note: When inserting we cannot hone the $fieldFilters parameters 00435 00436 $use_fields = array_diff( array_keys( $fields ), $exclude_fields ); 00437 $use_field_names = $use_fields; 00438 if ( $db->useShortNames() ) 00439 { 00440 $use_short_field_names = $use_field_names; 00441 eZPersistentObject::replaceFieldsWithShortNames( $db, $fields, $use_short_field_names ); 00442 $field_text = implode( ', ', $use_short_field_names ); 00443 unset( $use_short_field_names ); 00444 } 00445 else 00446 $field_text = implode( ', ', $use_field_names ); 00447 00448 $use_values_hash = array(); 00449 $escapeFields = array_diff( $use_fields, $doNotEscapeFields ); 00450 00451 foreach ( $escapeFields as $key ) 00452 { 00453 $value = $obj->attribute( $key ); 00454 $field_def = $fields[$key]; 00455 00456 if ( $field_def['datatype'] == 'float' || $field_def['datatype'] == 'double' ) 00457 { 00458 if ( $value === null ) 00459 { 00460 $use_values_hash[$key] = 'NULL'; 00461 } 00462 else 00463 { 00464 $use_values_hash[$key] = sprintf( '%F', $value ); 00465 } 00466 } 00467 else if ( $field_def['datatype'] == 'int' || $field_def['datatype'] == 'integer' ) 00468 { 00469 if ( $value === null ) 00470 { 00471 $use_values_hash[$key] = 'NULL'; 00472 } 00473 else 00474 { 00475 $use_values_hash[$key] = sprintf( '%d', $value ); 00476 } 00477 } 00478 else 00479 { 00480 // Note: for more colherence, we might use NULL for sql strings if the php value is NULL and not an empty sring 00481 // but to keep compatibility with ez db, where most string columns are "not null default ''", 00482 // and code feeding us a php null value without meaning it, we do not. 00483 $use_values_hash[$key] = "'" . $db->escapeString( $value ) . "'"; 00484 } 00485 } 00486 foreach ( $doNotEscapeFields as $key ) 00487 { 00488 $use_values_hash[$key] = $changedValueFields[$key]; 00489 } 00490 $use_values = array(); 00491 foreach ( $use_field_names as $field ) 00492 $use_values[] = $use_values_hash[$field]; 00493 unset( $use_values_hash ); 00494 $value_text = implode( ", ", $use_values ); 00495 00496 $sql = "INSERT INTO $table ($field_text) VALUES($value_text)"; 00497 $db->query( $sql ); 00498 00499 if ( isset( $def["increment_key"] ) && 00500 is_string( $def["increment_key"] ) && 00501 !( $obj->attribute( $def["increment_key"] ) > 0 ) ) 00502 { 00503 $inc = $def["increment_key"]; 00504 $id = $db->lastSerialID( $table, $inc ); 00505 if ( $id !== false ) 00506 $obj->setAttribute( $inc, $id ); 00507 } 00508 } 00509 else 00510 { 00511 $use_fields = array_diff( array_keys( $fields ), array_merge( $keys, $exclude_fields ) ); 00512 if ( count( $use_fields ) > 0 ) 00513 { 00514 // If we filter out some of the fields we need to intersect it with $use_fields 00515 if ( is_array( $fieldFilters ) ) 00516 $use_fields = array_intersect( $use_fields, $fieldFilters ); 00517 $use_field_names = array(); 00518 foreach ( $use_fields as $key ) 00519 { 00520 if ( $db->useShortNames() && is_array( $fields[$key] ) && array_key_exists( 'short_name', $fields[$key] ) && strlen( $fields[$key]['short_name'] ) > 0 ) 00521 $use_field_names[$key] = $fields[$key]['short_name']; 00522 else 00523 $use_field_names[$key] = $key; 00524 } 00525 00526 $field_text = ""; 00527 $field_text_len = 0; 00528 $i = 0; 00529 00530 00531 foreach ( $use_fields as $key ) 00532 { 00533 $value = $obj->attribute( $key ); 00534 00535 if ( $fields[$key]['datatype'] == 'float' || $fields[$key]['datatype'] == 'double' ) 00536 { 00537 if ( $value === null ) 00538 $field_text_entry = $use_field_names[$key] . '=NULL'; 00539 else 00540 $field_text_entry = $use_field_names[$key] . "=" . sprintf( '%F', $value ); 00541 } 00542 else if ($fields[$key]['datatype'] == 'int' || $fields[$key]['datatype'] == 'integer' ) 00543 { 00544 if ( $value === null ) 00545 $field_text_entry = $use_field_names[$key] . '=NULL'; 00546 else 00547 $field_text_entry = $use_field_names[$key] . "=" . sprintf( '%d', $value ); 00548 } 00549 else if ( in_array( $use_field_names[$key], $doNotEscapeFields ) ) 00550 { 00551 $field_text_entry = $use_field_names[$key] . "=" . $changedValueFields[$key]; 00552 } 00553 else 00554 { 00555 $field_text_entry = $use_field_names[$key] . "='" . $db->escapeString( $value ) . "'"; 00556 } 00557 00558 $field_text_len += strlen( $field_text_entry ); 00559 $needNewline = false; 00560 if ( $field_text_len > 60 ) 00561 { 00562 $needNewline = true; 00563 $field_text_len = 0; 00564 } 00565 if ( $i > 0 ) 00566 $field_text .= "," . ($needNewline ? "\n " : ' '); 00567 $field_text .= $field_text_entry; 00568 ++$i; 00569 } 00570 $cond_text = eZPersistentObject::conditionText( $key_conds ); 00571 $sql = "UPDATE $table SET $field_text$cond_text"; 00572 $db->query( $sql ); 00573 } 00574 } 00575 $obj->setHasDirtyData( false ); 00576 } 00577 00578 /** 00579 * Calls conditionTextByRow with an empty row and $conditions. 00580 * 00581 * @param array $conditions 00582 * @return string 00583 */ 00584 public static function conditionText( $conditions ) 00585 { 00586 return eZPersistentObject::conditionTextByRow( $conditions, null ); 00587 } 00588 00589 /** 00590 * Generates an SQL sentence from the conditions \a $conditions and 00591 * row data $row. 00592 * 00593 * If $row is empty (or null) it uses the condition data instead of row data. 00594 * 00595 * @param array $conditions 00596 * @param array|null $row 00597 * @return string 00598 */ 00599 public static function conditionTextByRow( $conditions, $row ) 00600 { 00601 $db = eZDB::instance(); 00602 00603 $where_text = ""; 00604 if ( is_array( $conditions ) and 00605 count( $conditions ) > 0 ) 00606 { 00607 $where_text = " WHERE "; 00608 $i = 0; 00609 foreach ( $conditions as $id => $cond ) 00610 { 00611 if ( $i > 0 ) 00612 $where_text .= " AND "; 00613 if ( is_array( $row ) ) 00614 { 00615 $where_text .= $cond . "='" . $db->escapeString( $row[$cond] ) . "'"; 00616 } 00617 else 00618 { 00619 if ( is_array( $cond ) ) 00620 { 00621 if ( is_array( $cond[0] ) ) 00622 { 00623 $where_text .= $id . ' IN ( '; 00624 $j = 0; 00625 foreach ( $cond[0] as $value ) 00626 { 00627 if ( $j > 0 ) 00628 $where_text .= ", "; 00629 $where_text .= "'" . $db->escapeString( $value ) . "'"; 00630 ++$j; 00631 } 00632 $where_text .= ' ) '; 00633 } 00634 else if ( is_array( $cond[1] ) ) 00635 { 00636 $range = $cond[1]; 00637 $where_text .= "$id BETWEEN '" . $db->escapeString( $range[0] ) . "' AND '" . $db->escapeString( $range[1] ) . "'"; 00638 } 00639 else 00640 { 00641 switch ( $cond[0] ) 00642 { 00643 case '>=': 00644 case '<=': 00645 case '<': 00646 case '>': 00647 case '=': 00648 case '<>': 00649 case '!=': 00650 case 'like': 00651 { 00652 $where_text .= $db->escapeString( $id ) . " " . $cond[0] . " '" . $db->escapeString( $cond[1] ) . "'"; 00653 } break; 00654 default: 00655 { 00656 eZDebug::writeError( "Conditional operator '$cond[0]' is not supported.", __METHOD__ ); 00657 } break; 00658 } 00659 00660 } 00661 } 00662 else 00663 $where_text .= $db->escapeString( $id ) . "='" . $db->escapeString( $cond ) . "'"; 00664 } 00665 ++$i; 00666 } 00667 } 00668 return $where_text; 00669 } 00670 00671 /** 00672 * Creates an SQL query out of the different parameters and returns an array with the result. 00673 * 00674 * A full example: 00675 * <code> 00676 * $filter = array( 'id', 'name' ); 00677 * $conds = array( 'type' => 5, 00678 * 'size' => array( false, array( 200, 500 ) ) ); 00679 * $sorts = array( 'name' => 'asc' ); 00680 * $limit = array( 'offset' => 50, 'length' => 10 ); 00681 * eZPersistentObject::fetchObjectList( $def, $filter, $conds, $sorts, $limit, true, false, null ) 00682 * </code> 00683 * 00684 * Counting number of elements. 00685 * <code> 00686 * $custom = array( array( 'operation' => 'count( id )', 00687 * 'name' => 'count' ) ); 00688 * // Here $field_filters is set to an empty array, that way only count is used in fields 00689 * $rows = eZPersistentObject::fetchObjectList( $def, array(), null, null, null, false, false, $custom ); 00690 * return $rows[0]['count']; 00691 * </code> 00692 * 00693 * Counting elements per type using grouping 00694 * <code> 00695 * $custom = array( array( 'operation' => 'count( id )', 00696 * 'name' => 'count' ) ); 00697 * $group = array( 'type' ); 00698 * $rows = eZPersistentObject::fetchObjectList( $def, array(), null, null, null, false, $group, $custom ); 00699 * return $rows[0]['count']; 00700 * </code> 00701 * 00702 * Example to fetch a result with custom conditions. The following example will fetch the attributes to 00703 * the contentobject with id 1 and add the contentobject.name in each attribute row with the array key 00704 * contentobject_name. 00705 * <code> 00706 * $objectDef = eZContentObject::definition(); 00707 * $objectAttributeDef = eZContentObjectAttribute::definition(); 00708 * 00709 * $fields = array(); 00710 * $conds = array( $objectDef['name'] . '.id' => 1 ); 00711 * $sorts = array( $objectAttributeDef['name'] . '.sort_key_string' => 'asc' ); 00712 * 00713 * $limit = null; 00714 * $asObject = false; 00715 * $group = false; 00716 * 00717 * $customFields = array( $objectAttributeDef['name'] . '.*', 00718 * array( 'operation' => $objectDef['name'] . '.name', 00719 * 'name' => 'contentobject_name' ) ); 00720 * 00721 * $customTables = array( $objectDef['name'] ); 00722 * 00723 * $languageCode = 'eng-GB'; 00724 * $customConds = ' AND ' . $objectDef['name'] . '.current_version=' . $objectAttributeDef['name'] . '.version' . 00725 * ' AND ' . $objectDef['name'] . '.id=' . $objectAttributeDef['name'] . '.contentobject_id' . 00726 * ' AND ' . $objectAttributeDef['name'] . '.language_code=\'' . $languageCode . '\''; 00727 * 00728 * $rows = eZPersistentObject::fetchObjectList( $objectAttributeDef, $fields, $conds, $sorts, $limit, $asObject, 00729 * $group, $customFields, $customTables, $customConds ); 00730 * </code> 00731 * 00732 * @param array $def A definition array of all fields, table name and sorting (see {@link eZPersistentObject::definition()} for more info) 00733 * @param array|null $field_filters If defined determines the fields which are extracted (array of field names), if not all fields are fetched 00734 * @param array|null $conds null for no special condition or an associative array of fields to filter on. 00735 * Syntax is FIELD => CONDITION 00736 * CONDITION can be one of: 00737 * - Scalar value: Creates a condition where FIELD must match the value, e.g 00738 * <code>array( 'id' => 5 )</code> generates <code>SQL id = 5</code> 00739 * - Array with two scalar values: The first value is the match operator, the second is the scalar value 00740 * <code>array( 'priority' => array( '>', 5 ) )</code> generates SQL <code>priority > 5</code> 00741 * - Array with range: The first value is <code>false</code>, the second value is an array with start and stop of range in array 00742 * <code>array( 'type' => array( false, array( 1, 5 ) ) )</code> generates SQL <code>type BETWEEN 1 AND 5</code> 00743 * - Array with multiple elements: The first value is the field identifier, the second is an array with scalar values 00744 * <code>array( 'id' => array( array( 1, 5, 7 ) ) )</code> generates SQL <code>id IN ( 1, 5, 7 )</code> 00745 * @param array|null|bool $sorts An associative array of sorting conditions, if set to false ignores settings in $def, if set to null uses settingss in $def. 00746 * Syntax is FIELD => DIRECTION. 00747 * DIRECTION must either be 'asc' for ascending or 'desc' for descending. 00748 * @param array|null $limit An associative array with limitiations, can contain 00749 * - 'offset': Numerical value defining the start offset for the fetch 00750 * - 'length': Numerical value defining the max number of items to return 00751 * @param bool $asObject If true then it will return an array with objects, objects are created from class defined in $def. 00752 * If falseit will just return the rows fetch from database. 00753 * @param array|null|bool $grouping An array of fields to group by or null to use grouping in defintion $def. 00754 * @param null $custom_fields Array of FIELD elements to add to SQL, can be used to perform custom fetches, e.g counts. 00755 * FIELD is an associative array containing: 00756 * - 'operation': A text field which is included in the field list 00757 * - 'name': If present it adds <code>AS name</code> to the operation. 00758 * @param array|null $custom_tables Array of additional tables 00759 * @param string|null $custom_conds String with sql conditions for 'WHERE' clause. 00760 * @return eZPersistentObject[]|array|null An array of objects or rows, null on error 00761 */ 00762 public static function fetchObjectList( $def, 00763 $field_filters = null, 00764 $conds = null, 00765 $sorts = null, 00766 $limit = null, 00767 $asObject = true, 00768 $grouping = false, 00769 $custom_fields = null, 00770 $custom_tables = null, 00771 $custom_conds = null ) 00772 { 00773 $db = eZDB::instance(); 00774 $fields = $def["fields"]; 00775 $tables = $def["name"]; 00776 $class_name = $def["class_name"]; 00777 if ( is_array( $custom_tables ) ) 00778 { 00779 foreach( $custom_tables as $custom_table ) 00780 $tables .= ', ' . $db->escapeString( $custom_table ); 00781 } 00782 eZPersistentObject::replaceFieldsWithShortNames( $db, $fields, $conds ); 00783 if ( is_array( $field_filters ) ) 00784 $field_array = array_unique( array_intersect( 00785 $field_filters, array_keys( $fields ) ) ); 00786 else 00787 $field_array = array_keys( $fields ); 00788 if ( $custom_fields !== null and is_array( $custom_fields ) ) 00789 { 00790 foreach( $custom_fields as $custom_field ) 00791 { 00792 if ( is_array( $custom_field ) ) 00793 { 00794 $custom_text = $custom_field["operation"]; 00795 if ( isset( $custom_field["name"] ) ) 00796 { 00797 $field_name = $custom_field["name"]; 00798 $custom_text .= " AS $field_name"; 00799 } 00800 } 00801 else 00802 { 00803 $custom_text = $custom_field; 00804 } 00805 $field_array[] = $custom_text; 00806 } 00807 } 00808 eZPersistentObject::replaceFieldsWithShortNames( $db, $fields, $field_array ); 00809 $field_text = ''; 00810 $i = 0; 00811 foreach ( $field_array as $field_item ) 00812 { 00813 if ( ( $i % 7 ) == 0 and 00814 $i > 0 ) 00815 $field_text .= ", "; 00816 else if ( $i > 0 ) 00817 $field_text .= ', '; 00818 $field_text .= $field_item; 00819 ++$i; 00820 } 00821 00822 $where_text = eZPersistentObject::conditionText( $conds ); 00823 if ( $custom_conds ) 00824 $where_text .= $custom_conds; 00825 00826 $sort_text = ""; 00827 if ( $sorts !== false and ( isset( $def["sort"] ) or is_array( $sorts ) ) ) 00828 { 00829 $sort_list = array(); 00830 if ( is_array( $sorts ) ) 00831 { 00832 $sort_list = $sorts; 00833 } 00834 else if ( isset( $def['sort'] ) ) 00835 { 00836 $sort_list = $def["sort"]; 00837 } 00838 if ( count( $sort_list ) > 0 ) 00839 { 00840 $sort_text = " ORDER BY "; 00841 $i = 0; 00842 foreach ( $sort_list as $sort_id => $sort_type ) 00843 { 00844 if ( $i > 0 ) 00845 $sort_text .= ", "; 00846 if ( $sort_type == "desc" ) 00847 $sort_text .= "$sort_id DESC"; 00848 else 00849 $sort_text .= "$sort_id ASC"; 00850 ++$i; 00851 } 00852 } 00853 } 00854 00855 $grouping_text = ""; 00856 if ( isset( $def["grouping"] ) or ( is_array( $grouping ) and count( $grouping ) > 0 ) ) 00857 { 00858 $grouping_list = isset( $def["grouping"] ) ? $def["grouping"] : array(); 00859 if ( is_array( $grouping ) ) 00860 $grouping_list = $grouping; 00861 if ( count( $grouping_list ) > 0 ) 00862 { 00863 $grouping_text = " GROUP BY "; 00864 $i = 0; 00865 foreach ( $grouping_list as $grouping_id ) 00866 { 00867 if ( $i > 0 ) 00868 $grouping_text .= ", "; 00869 $grouping_text .= "$grouping_id"; 00870 ++$i; 00871 } 00872 } 00873 } 00874 00875 $db_params = array(); 00876 if ( is_array( $limit ) ) 00877 { 00878 if ( isset( $limit["offset"] ) ) 00879 { 00880 $db_params["offset"] = $limit["offset"]; 00881 } 00882 if ( isset( $limit['limit'] ) ) 00883 { 00884 $db_params["limit"] = $limit["limit"]; 00885 } 00886 else 00887 { 00888 $db_params["limit"] = $limit["length"]; 00889 } 00890 } 00891 00892 $sqlText = "SELECT $field_text 00893 FROM $tables" . 00894 $where_text . 00895 $grouping_text . 00896 $sort_text; 00897 $rows = $db->arrayQuery( $sqlText, 00898 $db_params ); 00899 00900 // Indicate that a DB error occured. 00901 if ( $rows === false ) 00902 return null; 00903 00904 $objectList = eZPersistentObject::handleRows( $rows, $class_name, $asObject ); 00905 return $objectList; 00906 } 00907 00908 /** 00909 * Creates PHP objects out of the database rows $rows. 00910 * 00911 * Each object is created from class \$ class_name and is passed 00912 * as a row array as parameter. 00913 * 00914 * @param array $rows 00915 * @param string $class_name 00916 * @param bool $asObject If true then objects will be created, if not it just returns $rows as it is. 00917 * @return eZPersistentObject[]|array 00918 */ 00919 public static function handleRows( $rows, $class_name, $asObject ) 00920 { 00921 if ( $asObject ) 00922 { 00923 $objects = array(); 00924 if ( is_array( $rows ) ) 00925 { 00926 foreach ( $rows as $row ) 00927 { 00928 $objects[] = new $class_name( $row ); 00929 } 00930 } 00931 return $objects; 00932 } 00933 else 00934 return $rows; 00935 } 00936 00937 /** 00938 * Sets row id $id2 to have the placement of row id $id1. 00939 * 00940 * Note: Transaction unsafe. If you call several transaction unsafe methods 00941 * you must enclose the calls within a db transaction; thus within db->begin 00942 * and db->commit. 00943 * 00944 * @param string $table 00945 * @param array $keys 00946 * @param int $order_id 00947 * @param array $rows 00948 * @param int $id1 00949 * @param int $id2 00950 * @return string 00951 */ 00952 public static function swapRow( $table, $keys, $order_id, $rows, $id1, $id2 ) 00953 { 00954 $db = eZDB::instance(); 00955 $text = $order_id . "='" . $db->escapeString( $rows[$id1][$order_id] ) . "' WHERE "; 00956 $i = 0; 00957 foreach ( $keys as $key ) 00958 { 00959 if ( $i > 0 ) 00960 $text .= " AND "; 00961 $text .= $key . "='" . $db->escapeString( $rows[$id2][$key] ) . "'"; 00962 ++$i; 00963 } 00964 return "UPDATE $table SET $text"; 00965 } 00966 00967 /** 00968 * Returns an order value which can be used for new items in table, 00969 * for instance placement. 00970 * 00971 * Uses $def, $orderField and $conditions to figure out the currently maximum 00972 * order value and returns one that is larger. 00973 * 00974 * @param array $def A definition array of all fields, table name and sorting (see {@link eZPersistentObject::definition()} for more info) 00975 * @param string $orderField 00976 * @param array $conditions 00977 * @return int 00978 */ 00979 public static function newObjectOrder( $def, $orderField, $conditions ) 00980 { 00981 $db = eZDB::instance(); 00982 $table = $def["name"]; 00983 $keys = $def["keys"]; 00984 00985 $cond_text = eZPersistentObject::conditionText( $conditions ); 00986 $rows = $db->arrayQuery( "SELECT MAX($orderField) AS $orderField FROM $table $cond_text" ); 00987 if ( count( $rows ) > 0 and isset( $rows[0][$orderField] ) ) 00988 return $rows[0][$orderField] + 1; 00989 else 00990 return 1; 00991 } 00992 00993 /** 00994 * Moves a row in a database table. 00995 * 00996 * Uses $orderField to determine the order of objects in a table, usually this 00997 * is a placement of some kind. It uses this order field to figure out how move 00998 * the row, the row is either swapped with another row which is either above or 00999 * below according to whether $down is true or false, or it is swapped 01000 * with the first item or the last item depending on whether this row 01001 * is first or last. 01002 * Uses $conditions to figure out unique rows. 01003 * 01004 * Note: Transaction unsafe. If you call several transaction unsafe methods 01005 * you must enclose the calls within a db transaction; thus within db->begin 01006 * and db->commit. 01007 * 01008 * @param array $def A definition array of all fields, table name and sorting (see {@link eZPersistentObject::definition()} for more info) 01009 * @param array $orderField Associative array with one element, the key is the order id and values is order value. 01010 * @param array $conditions 01011 * @param bool $down 01012 * @return void 01013 */ 01014 public static function reorderObject( $def, $orderField, $conditions, $down = true ) 01015 { 01016 $db = eZDB::instance(); 01017 $table = $def["name"]; 01018 $keys = $def["keys"]; 01019 01020 reset( $orderField ); 01021 $order_id = key( $orderField ); 01022 $order_val = $orderField[$order_id]; 01023 if ( $down ) 01024 { 01025 $order_operator = ">="; 01026 $order_type = "asc"; 01027 $order_add = -1; 01028 } 01029 else 01030 { 01031 $order_operator = "<="; 01032 $order_type = "desc"; 01033 $order_add = 1; 01034 } 01035 $fields = array_merge( $keys, array( $order_id ) ); 01036 $rows = eZPersistentObject::fetchObjectList( $def, 01037 $fields, 01038 array_merge( $conditions, 01039 array( $order_id => array( $order_operator, 01040 $order_val ) ) ), 01041 array( $order_id => $order_type ), 01042 array( "length" => 2 ), 01043 false ); 01044 if ( count( $rows ) == 2 ) 01045 { 01046 $swapSQL1 = eZPersistentObject::swapRow( $table, $keys, $order_id, $rows, 1, 0 ); 01047 $swapSQL2 = eZPersistentObject::swapRow( $table, $keys, $order_id, $rows, 0, 1 ); 01048 $db->begin(); 01049 $db->query( $swapSQL1 ); 01050 $db->query( $swapSQL2 ); 01051 $db->commit(); 01052 } 01053 else 01054 { 01055 $tmp = eZPersistentObject::fetchObjectList( $def, 01056 $fields, 01057 $conditions, 01058 array( $order_id => $order_type ), 01059 array( "length" => 1 ), 01060 false ); 01061 $where_text = eZPersistentObject::conditionTextByRow( $keys, $rows[0] ); 01062 $db->query( "UPDATE $table SET $order_id='" . ( $tmp[0][$order_id] + $order_add ) . 01063 "'$where_text" ); 01064 } 01065 } 01066 01067 /** 01068 * Returns the definition for the object, the default implementation 01069 * is to return an empty array. It's upto each inheriting class 01070 * to return a proper definition array. 01071 * 01072 * The definition array is an associative array consists of these keys: 01073 * - fields: an associative array of fields which defines which database 01074 * field (the key) is to fetched and how they map to object 01075 * member variables (the value). 01076 * - keys: an array of fields which is used for uniquely identifying 01077 * the object in the table. 01078 * - function_attributes: an associative array of attributes which maps 01079 * to member functions, used for fetching 01080 * data with functions. 01081 * 01082 * - set_functions: an associative array of attributes which maps to member 01083 * functions, used for setting data with functions. 01084 * - increment_key: the field which is incremented on table inserts. 01085 * - class_name: the classname which is used for instantiating new objecs 01086 * when fetching from the database. 01087 * - sort: an associative array which defines the default sorting of lists, 01088 * the key is the table field while the value is the sorting method 01089 * which is either 'asc' or 'desc'. 01090 * - name: the name of the database table 01091 * 01092 * Example: 01093 * <code> 01094 * public static function definition() 01095 * { 01096 * return array( "fields" => array( "id" => "ID", 01097 * "version" => "Version", 01098 * "name" => "Name" ), 01099 * "keys" => array( "id", "version" ), 01100 * "function_attributes" => array( "current" => "currentVersion", 01101 * "class_name" => "className" ), 01102 * "increment_key" => "id", 01103 * "class_name" => "eZContentClass", 01104 * "sort" => array( "id" => "asc" ), 01105 * "name" => "ezcontentclass" ); 01106 * } 01107 * </code> 01108 * 01109 * @return array 01110 */ 01111 public static function definition() 01112 { 01113 return array(); 01114 } 01115 01116 /** 01117 * Escapes strings in an array with the help of {@link eZDBInterface::escapeString()} 01118 * 01119 * @param array $array 01120 * @return array 01121 */ 01122 public static function escapeArray( $array ) 01123 { 01124 $db = eZDB::instance(); 01125 $out = array(); 01126 foreach( $array as $key => $value ) 01127 { 01128 if ( is_array( $value ) ) 01129 { 01130 $tmp = array(); 01131 foreach( $value as $valueItem ) 01132 { 01133 $tmp[] = $db->escapeString( $valueItem ); 01134 } 01135 $out[$key] = $tmp; 01136 unset( $tmp ); 01137 } 01138 else 01139 $out[$key] = $db->escapeString( $value ); 01140 } 01141 return $out; 01142 } 01143 01144 /** 01145 * Updates rows matching the given parameters 01146 * 01147 * Note: Transaction unsafe. If you call several transaction unsafe methods 01148 * you must enclose the calls within a db transaction; thus within db->begin 01149 * and db->commit. 01150 * 01151 * @param array $parameters 01152 * @return void 01153 */ 01154 public static function updateObjectList( $parameters ) 01155 { 01156 $db = eZDB::instance(); 01157 $def = $parameters['definition']; 01158 $table = $def['name']; 01159 $fields = $def['fields']; 01160 $keys = $def['keys']; 01161 01162 $updateFields = $parameters['update_fields']; 01163 $conditions = $parameters['conditions']; 01164 01165 $query = "UPDATE $table SET "; 01166 $i = 0; 01167 $valueBound = false; 01168 01169 foreach( $updateFields as $field => $value ) 01170 { 01171 $fieldDef = $fields[ $field ]; 01172 $numericDataTypes = array( 'integer', 'float', 'double' ); 01173 if ( strlen( $value ) == 0 && 01174 is_array( $fieldDef ) && 01175 in_array( $fieldDef['datatype'], $numericDataTypes ) && 01176 array_key_exists( 'default', $fieldDef ) && 01177 $fieldDef[ 'default' ] !== null ) 01178 { 01179 $value = $fieldDef[ 'default' ]; 01180 } 01181 01182 $bindDataTypes = array( 'text' ); 01183 if ( $db->bindingType() != eZDBInterface::BINDING_NO && 01184 strlen( $value ) > 2000 && 01185 is_array( $fieldDef ) && 01186 in_array( $fieldDef['datatype'], $bindDataTypes ) 01187 ) 01188 { 01189 $value = $db->bindVariable( $value, $fieldDef ); 01190 $valueBound = true; 01191 } 01192 else 01193 $valueBound = false; 01194 01195 if ( $i > 0 ) 01196 $query .= ', '; 01197 if ( $valueBound ) 01198 $query .= $field . "=" . $value; 01199 else 01200 $query .= $field . "='" . $db->escapeString( $value ) . "'"; 01201 ++$i; 01202 } 01203 $query .= ' WHERE '; 01204 $i = 0; 01205 foreach( $conditions as $conditionKey => $condition ) 01206 { 01207 if ( $i > 0 ) 01208 $query .= ' AND '; 01209 if ( is_array( $condition ) ) 01210 { 01211 $query .= $conditionKey . ' IN ('; 01212 $j = 0; 01213 foreach( $condition as $conditionValue ) 01214 { 01215 if ( $j > 0 ) 01216 $query .= ', '; 01217 $query .= "'" . $db->escapeString( $conditionValue ) . "'"; 01218 ++$j; 01219 } 01220 $query .= ')'; 01221 } 01222 else 01223 $query .= $conditionKey . "='" . $db->escapeString( $condition ) . "'"; 01224 ++$i; 01225 } 01226 $db->query( $query ); 01227 } 01228 01229 /** 01230 * Returns the attributes for this object, taken from the definition fields 01231 * and function attributes. 01232 * 01233 * @see eZPersistentObject::definition() 01234 * 01235 * @return array 01236 */ 01237 public function attributes() 01238 { 01239 $def = $this->definition(); 01240 $attrs = array_keys( $def["fields"] ); 01241 if ( isset( $def["function_attributes"] ) ) 01242 $attrs = array_unique( array_merge( $attrs, array_keys( $def["function_attributes"] ) ) ); 01243 if ( isset( $def["functions"] ) ) 01244 $attrs = array_unique( array_merge( $attrs, array_keys( $def["functions"] ) ) ); 01245 return $attrs; 01246 } 01247 01248 /** 01249 * Checks if $attr is part of the definition fields or function attributes. 01250 * 01251 * @param string $attr 01252 * @return bool 01253 */ 01254 public function hasAttribute( $attr ) 01255 { 01256 $def = $this->definition(); 01257 $has_attr = isset( $def["fields"][$attr] ); 01258 if ( !$has_attr and isset( $def["function_attributes"] ) ) 01259 $has_attr = isset( $def["function_attributes"][$attr] ); 01260 if ( !$has_attr and isset( $def["functions"] ) ) 01261 $has_attr = isset( $def["functions"][$attr] ); 01262 return $has_attr; 01263 } 01264 01265 /** 01266 * Returns the attribute data for $attr, this is either returned from the 01267 * member variables or a member function depending on whether the definition 01268 * field or function attributes matched. 01269 * 01270 * @param string $attr 01271 * @param bool $noFunction 01272 * @return mixed 01273 */ 01274 public function attribute( $attr, $noFunction = false ) 01275 { 01276 $def = $this->definition(); 01277 $attrFunctions = isset( $def["function_attributes"] ) ? $def["function_attributes"] : null; 01278 if ( $noFunction === false && isset( $attrFunctions[$attr] ) ) 01279 { 01280 $functionName = $attrFunctions[$attr]; 01281 if ( method_exists( $this, $functionName ) ) 01282 { 01283 return $this->$functionName(); 01284 } 01285 01286 eZDebug::writeError( 'Could not find function : "' . get_class( $this ) . '::' . $functionName . '()".', __METHOD__ ); 01287 return null; 01288 } 01289 01290 $fields = $def["fields"]; 01291 if ( isset( $fields[$attr] ) ) 01292 { 01293 $attrName = $fields[$attr]; 01294 if ( isset( $attrName['name'] ) ) 01295 { 01296 $attrName = $attrName['name']; 01297 } 01298 return $this->$attrName; 01299 } 01300 01301 if ( isset( $def["functions"][$attr] ) ) 01302 { 01303 return $this->$functions[$attr](); 01304 } 01305 01306 eZDebug::writeError( "Attribute '$attr' does not exist", $def['class_name'] . '::attribute' ); 01307 return null; 01308 } 01309 01310 /** 01311 * Sets the attribute $attr to the value $val. 01312 * 01313 * The attribute must be present in the objects definition fields or set functions. 01314 * 01315 * @param string $attr 01316 * @param mixed $val 01317 * @return void 01318 */ 01319 public function setAttribute( $attr, $val ) 01320 { 01321 $def = $this->definition(); 01322 $fields = $def["fields"]; 01323 $functions = isset( $def["set_functions"] ) ? $def["set_functions"] : null; 01324 if ( isset( $fields[$attr] ) ) 01325 { 01326 $attrName = $fields[$attr]; 01327 if ( is_array( $attrName ) ) 01328 { 01329 $attrName = $attrName['name']; 01330 } 01331 01332 $oldValue = null; 01333 if ( isset( $this->$attrName ) ) 01334 $oldValue = $this->$attrName; 01335 $this->$attrName = $val; 01336 if ( $oldValue === null || 01337 $oldValue !== $val ) 01338 $this->setHasDirtyData( true ); 01339 } 01340 else if ( isset( $functions[$attr] ) ) 01341 { 01342 $functionName = $functions[$attr]; 01343 $oldValue = $this->$functionName( $val ); 01344 if ( $oldValue === null or $oldValue !== $val ) 01345 $this->setHasDirtyData( true ); 01346 } 01347 else 01348 { 01349 eZDebug::writeError( "Undefined attribute '$attr', cannot set", 01350 $def['class_name'] ); 01351 } 01352 } 01353 01354 /** 01355 * Returns true if the data is considered dirty and needs to be stored. 01356 * 01357 * @return bool 01358 */ 01359 public function hasDirtyData() 01360 { 01361 return $this->PersistentDataDirty; 01362 } 01363 01364 /** 01365 * Sets whether the object has dirty data or not. 01366 * 01367 * @param bool $hasDirtyData 01368 * @return void 01369 */ 01370 public function setHasDirtyData( $hasDirtyData ) 01371 { 01372 $this->PersistentDataDirty = $hasDirtyData; 01373 } 01374 01375 /** 01376 * Returns the short attribute name (alias) if it's defined, given attribute name otherwise 01377 * 01378 * @param eZDBInterface $db 01379 * @param array $def A definition array of all fields, table name and sorting (see {@link eZPersistentObject::definition()} for more info) 01380 * @param string $attrName 01381 * @return string 01382 */ 01383 public static function getShortAttributeName( $db, $def, $attrName ) 01384 { 01385 $fields = $def['fields']; 01386 01387 if ( $db->useShortNames() && isset( $fields[$attrName] ) && array_key_exists( 'short_name', $fields[$attrName] ) && $fields[$attrName]['short_name'] ) 01388 return $fields[$attrName]['short_name']; 01389 01390 return $attrName; 01391 } 01392 } 01393 01394 ?>