| [ Index ] |
|
Code source de eZ Publish 3.9.0 |
1 <?php 2 // 3 // Definition of eZPersistentObject class 4 // 5 // Created on: <16-Apr-2002 11:08:14 amos> 6 // 7 // SOFTWARE NAME: eZ publish 8 // SOFTWARE RELEASE: 3.9.0 9 // BUILD VERSION: 17785 10 // COPYRIGHT NOTICE: Copyright (C) 1999-2006 eZ systems AS 11 // SOFTWARE LICENSE: GNU General Public License v2.0 12 // NOTICE: > 13 // This program is free software; you can redistribute it and/or 14 // modify it under the terms of version 2.0 of the GNU General 15 // Public License as published by the Free Software Foundation. 16 // 17 // This program is distributed in the hope that it will be useful, 18 // but WITHOUT ANY WARRANTY; without even the implied warranty of 19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 // GNU General Public License for more details. 21 // 22 // You should have received a copy of version 2.0 of the GNU General 23 // Public License along with this program; if not, write to the Free 24 // Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, 25 // MA 02110-1301, USA. 26 // 27 // 28 29 /*! 30 \defgroup eZKernel Kernel system 31 */ 32 33 /*! 34 \class eZPersistentObject ezpersistentobject.php 35 \ingroup eZKernel 36 \brief Allows for object persistence in a database 37 38 Classes which stores simple types in databases should inherit from this 39 and implement the definition() function. The class will then get initialization, 40 fetching, listing, moving, storing and deleting for free as well as attribute 41 access. The new class must have a constructor which takes one parameter called 42 \c $row and pass that this constructor. 43 44 \code 45 class MyClass extends eZPersistentObject 46 { 47 function MyClass( $row ) 48 { 49 $this->eZPersistentObject( $row ); 50 } 51 } 52 \endcode 53 54 */ 55 56 include_once ( "lib/ezdb/classes/ezdb.php" ); 57 include_once ( "lib/ezutils/classes/ezdebug.php" ); 58 59 class eZPersistentObject 60 { 61 /*! 62 Initializes the object with the row \a $row. It will try to set 63 each field taken from the database row. Calls fill to do the job. 64 If the parameter \a $row is an integer it will try to fetch it 65 from the database using it as the unique ID. 66 */ 67 function eZPersistentObject( $row ) 68 { 69 $this->PersistentDataDirty = false; 70 if ( is_numeric( $row ) ) 71 $row = $this->fetch( $row, false ); 72 $this->fill( $row ); 73 } 74 75 /*! 76 Tries to fill in the data in the object by using the object definition 77 which is returned by the function definition() and the database row 78 data \a $row. Each field will be fetch from the definition and then 79 use that fieldname to fetch from the row and set the data. 80 */ 81 function fill( &$row ) 82 { 83 if ( $row == false ) 84 return; 85 $def = $this->definition(); 86 $fields =& $def["fields"]; 87 88 foreach ( $fields as $key => $value ) 89 { 90 $item = $fields[$key]; 91 if ( is_array( $item ) ) 92 { 93 $item = $item['name']; 94 } 95 $this->$item =& $row[$key]; 96 } 97 } 98 99 /*! 100 \private 101 \static 102 For the given array \a fields treats its keys (for associative array) or 103 values (for non-associative array) as table fields names and replaces them 104 with short names (aliases) found in \a fieldDefs. 105 */ 106 function replaceFieldsWithShortNames( &$db, &$fieldDefs, &$fields ) 107 { 108 if ( !$db->useShortNames() || !$fields ) 109 return; 110 111 $short_fields_names = array(); 112 foreach ( $fields as $key => $val ) 113 { 114 if( is_numeric( $key ) ) // $fields is not an associative array 115 { 116 if ( array_key_exists( $val, $fieldDefs ) && 117 array_key_exists( 'short_name', $fieldDefs[$val] ) ) 118 { 119 $short_fields_names[$key] = $fieldDefs[$val]['short_name']; 120 } 121 else 122 $short_fields_names[$key] = $val; 123 } 124 else // $fields is an associative array 125 { 126 if ( array_key_exists( $key, $fieldDefs ) && 127 array_key_exists( 'short_name', $fieldDefs[$key] ) ) 128 { 129 $newkey = $fieldDefs[$key]['short_name']; 130 } 131 else 132 $newkey = $key; 133 $short_fields_names[$newkey] = $val; 134 } 135 136 } 137 $fields = $short_fields_names; 138 } 139 140 /*! 141 Creates an SQL query out of the different parameters and returns an object with the result. 142 If \a $asObject is true the returned item is an object otherwise a db row. 143 Uses fetchObjectList for the actual SQL handling and just returns the first row item. 144 145 See fetchObjectList() for a full description of the input parameters. 146 */ 147 function fetchObject( /*! The definition structure */ 148 &$def, 149 /*! If defined determines the fields which are extracted, if not all fields are fetched */ 150 $field_filters, 151 /*! An array of conditions which determines which rows are fetched*/ 152 $conds, 153 $asObject = true, 154 /*! An array of elements to group by */ 155 $grouping = null, 156 /*! An array of extra fields to fetch, each field may be a SQL operation */ 157 $custom_fields = null ) 158 { 159 $rows = eZPersistentObject::fetchObjectList( $def, $field_filters, $conds, 160 array(), null, $asObject, 161 $grouping, $custom_fields ); 162 if ( $rows ) 163 return $rows[0]; 164 return null; 165 } 166 167 /*! 168 Removes the object from the database, it will use the keys in the object 169 definition to figure out which table row should be removed unless \a $conditions 170 is defined as an array with fieldnames. 171 It uses removeObject to do the real job and passes the object defintion, 172 conditions and extra conditions \a $extraConditions to this function. 173 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 174 the calls within a db transaction; thus within db->begin and db->commit. 175 */ 176 function remove( $conditions = null, $extraConditions = null ) 177 { 178 $def = $this->definition(); 179 $keys =& $def["keys"]; 180 if ( !is_array( $conditions ) ) 181 { 182 $conditions = array(); 183 foreach ( $keys as $key ) 184 { 185 $value =& $this->attribute( $key ); 186 $conditions[$key] =& $value; 187 } 188 } 189 eZPersistentObject::removeObject( $def, $conditions, $extraConditions ); 190 } 191 192 /*! 193 Deletes the object from the table defined in \a $def with conditions \a $conditions 194 and extra conditions \a $extraConditions. The extra conditions will either be 195 appended to the existing conditions or overwrite existing fields. 196 Uses conditionText() to create the condition SQL. 197 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 198 the calls within a db transaction; thus within db->begin and db->commit. 199 */ 200 function removeObject( &$def, $conditions = null, $extraConditions = null ) 201 { 202 $db =& eZDB::instance(); 203 204 $table =& $def["name"]; 205 if ( is_array( $extraConditions ) ) 206 { 207 foreach ( $extraConditions as $key => $cond ) 208 { 209 $conditions[$key] = $cond; 210 } 211 } 212 213 /* substitute fields mentioned the conditions whith their 214 short names (if any) 215 */ 216 $fields =& $def['fields']; 217 eZPersistentObject::replaceFieldsWithShortNames( $db, $fields, $conditions ); 218 219 $cond_text = eZPersistentObject::conditionText( $conditions ); 220 221 $db->query( "DELETE FROM $table $cond_text" ); 222 } 223 224 /*! 225 Stores the object in the database, uses storeObject() to do the actual 226 job and passes \a $fieldFilters to it. 227 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 228 the calls within a db transaction; thus within db->begin and db->commit. 229 */ 230 function store( $fieldFilters = null ) 231 { 232 eZPersistentObject::storeObject( $this, $fieldFilters ); 233 } 234 235 /*! 236 Makes sure data is stored if the data is considered dirty. 237 \sa hasDirtyData 238 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 239 the calls within a db transaction; thus within db->begin and db->commit. 240 */ 241 function sync( $fieldFilters = null ) 242 { 243 if ( $this->hasDirtyData() ) 244 $this->store( $fieldFilters ); 245 } 246 247 /*! 248 \private 249 Stores the data in \a $obj to database. 250 \param fieldFilters If specified only certain fields will be stored. 251 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 252 the calls within a db transaction; thus within db->begin and db->commit. 253 */ 254 function storeObject( &$obj, $fieldFilters = null ) 255 { 256 $db =& eZDB::instance(); 257 $useFieldFilters = ( isset( $fieldFilters ) && is_array( $fieldFilters ) && $fieldFilters ); 258 259 $def = $obj->definition(); 260 $fields =& $def["fields"]; 261 $keys =& $def["keys"]; 262 $table =& $def["name"]; 263 $relations =& $def["relations"]; 264 $insert_object = false; 265 $exclude_fields = array(); 266 foreach ( $keys as $key ) 267 { 268 $value =& $obj->attribute( $key ); 269 if ( is_null( $value ) ) 270 { 271 $insert_object = true; 272 $exclude_fields[] = $key; 273 } 274 } 275 276 if ( $useFieldFilters ) 277 $insert_object = false; 278 279 $use_fields = array_diff( array_keys( $fields ), $exclude_fields ); 280 // If we filter out some of the fields we need to intersect it with $use_fields 281 if ( is_array( $fieldFilters ) ) 282 $use_fields = array_intersect( $use_fields, $fieldFilters ); 283 $doNotEscapeFields = array(); 284 $changedValueFields = array(); 285 $numericDataTypes = array( 'integer', 'float', 'double' ); 286 287 foreach ( $use_fields as $field_name ) 288 { 289 $field_def = $fields[$field_name]; 290 $value =& $obj->attribute( $field_name ); 291 292 if ( is_null( $value ) ) 293 { 294 if ( ! is_array( $field_def ) ) 295 { 296 $exclude_fields[] = $field_name; 297 } 298 else 299 { 300 if ( array_key_exists( 'default', $field_def ) && 301 (! is_null( $field_def['default'] ) || 302 ( $field_name == 'data_int' && 303 array_key_exists( 'required', $field_def ) && 304 $field_def[ 'required' ] == false ) ) ) 305 { 306 $obj->setAttribute( $field_name, $field_def[ 'default' ] ); 307 } 308 else 309 { 310 //if ( in_array( $field_def['datatype'], $numericDataTypes ) 311 $exclude_fields[] = $field_name; 312 } 313 } 314 } 315 316 if ( strlen( $value ) == 0 && 317 is_array( $field_def ) && 318 in_array( $field_def['datatype'], $numericDataTypes ) && 319 array_key_exists( 'default', $field_def ) && 320 !is_null( $field_def[ 'default' ] ) ) 321 { 322 $obj->setAttribute( $field_name, $field_def[ 'default' ] ); 323 } 324 325 if ( !is_null( $value ) && 326 $field_def['datatype'] === 'string' && 327 array_key_exists( 'max_length', $field_def ) && 328 $field_def['max_length'] > 0 && 329 strlen( $value ) > $field_def['max_length'] ) 330 { 331 $obj->setAttribute( $field_name, substr( $value, 0, $field_def['max_length'] ) ); 332 eZDebug::writeDebug( $value, "truncation of $field_name to max_length=". $field_def['max_length'] ); 333 } 334 $bindDataTypes = array( 'text' ); 335 if ( $db->bindingType() != EZ_DB_BINDING_NO && 336 strlen( $value ) > 2000 && 337 is_array( $field_def ) && 338 in_array( $field_def['datatype'], $bindDataTypes ) 339 ) 340 { 341 $boundValue = $db->bindVariable( $value, $field_def ); 342 // $obj->setAttribute( $field_name, $value ); 343 $doNotEscapeFields[] = $field_name; 344 $changedValueFields[$field_name] = $boundValue; 345 } 346 347 } 348 $key_conds = array(); 349 foreach ( $keys as $key ) 350 { 351 $value =& $obj->attribute( $key ); 352 $key_conds[$key] = $value; 353 } 354 unset( $value ); 355 356 $important_keys = $keys; 357 if ( is_array( $relations ) ) 358 { 359 // $important_keys = array(); 360 foreach( $relations as $relation => $relation_data ) 361 { 362 if ( !in_array( $relation, $keys ) ) 363 $important_keys[] = $relation; 364 } 365 } 366 if ( count( $important_keys ) == 0 && !$useFieldFilters ) 367 { 368 $insert_object = true; 369 } 370 else if ( !$insert_object ) 371 { 372 $rows = eZPersistentObject::fetchObjectList( $def, $keys, $key_conds, 373 array(), null, false, 374 null, null ); 375 if ( count( $rows ) == 0 ) 376 { 377 /* If we only want to update some fields in a record 378 * and that records does not exist, then we should do nothing, only return. 379 */ 380 if ( $useFieldFilters ) 381 return; 382 383 $insert_object = true; 384 } 385 } 386 387 if ( $insert_object ) 388 { 389 // We include compat.php here because of the ezsprintf function call below 390 require_once ( 'lib/compat.php' ); 391 392 // Note: When inserting we cannot hone the $fieldFilters parameters 393 394 $use_fields = array_diff( array_keys( $fields ), $exclude_fields ); 395 $use_field_names = $use_fields; 396 if ( $db->useShortNames() ) 397 { 398 $use_short_field_names = $use_field_names; 399 eZPersistentObject::replaceFieldsWithShortNames( $db, $fields, $use_short_field_names ); 400 $field_text = implode( ', ', $use_short_field_names ); 401 unset( $use_short_field_names ); 402 } 403 else 404 $field_text = implode( ', ', $use_field_names ); 405 406 $use_values_hash = array(); 407 $escapeFields = array_diff( $use_fields, $doNotEscapeFields ); 408 409 foreach ( $escapeFields as $key ) 410 { 411 $value = $obj->attribute( $key ); 412 $field_def = $fields[$key]; 413 414 if ( $field_def['datatype'] == 'float' ) 415 { 416 $value = ezsprintf( '%F', $value ); 417 } 418 if (is_null($value) && 419 $key == 'data_int' ) 420 { 421 $use_values_hash[$key] = 'NULL'; 422 } 423 else 424 { 425 $use_values_hash[$key] = "'" . $db->escapeString( $value ) . "'"; 426 } 427 } 428 foreach ( $doNotEscapeFields as $key ) 429 { 430 $value =& $changedValueFields[$key]; 431 $use_values_hash[$key] = $value; 432 } 433 $use_values = array(); 434 foreach ( $use_field_names as $field ) 435 $use_values[] = $use_values_hash[$field]; 436 unset( $use_values_hash ); 437 $value_text = implode( ", ", $use_values ); 438 439 $sql = "INSERT INTO $table ($field_text) VALUES($value_text)"; 440 $db->query( $sql ); 441 442 if ( isset( $def["increment_key"] ) && !($obj->attribute( $def["increment_key"]) > 0) ) 443 { 444 $inc =& $def["increment_key"]; 445 $id = $db->lastSerialID( $table, $inc ); 446 if ( $id !== false ) 447 $obj->setAttribute( $inc, $id ); 448 } 449 } 450 else 451 { 452 $use_fields = array_diff( array_keys( $fields ), array_merge( $keys, $exclude_fields ) ); 453 if ( count( $use_fields ) > 0 ) 454 { 455 // We include compat.php here because of the ezsprintf function call below 456 require_once ( 'lib/compat.php' ); 457 458 // If we filter out some of the fields we need to intersect it with $use_fields 459 if ( is_array( $fieldFilters ) ) 460 $use_fields = array_intersect( $use_fields, $fieldFilters ); 461 $use_field_names = array(); 462 foreach ( $use_fields as $key ) 463 { 464 if ( $db->useShortNames() && is_array( $fields[$key] ) && array_key_exists( 'short_name', $fields[$key] ) && strlen( $fields[$key]['short_name'] ) > 0 ) 465 $use_field_names[$key] = $fields[$key]['short_name']; 466 else 467 $use_field_names[$key] = $key; 468 } 469 470 $field_text = ""; 471 $field_text_len = 0; 472 $i = 0; 473 474 475 foreach ( $use_fields as $key ) 476 { 477 $value = $obj->attribute( $key ); 478 479 if ( $fields[$key]['datatype'] == 'float' ) 480 { 481 $value = ezsprintf( '%F', $value ); 482 } 483 484 if (is_null($value) && $key == 'data_int' ) 485 { 486 $field_text_entry = $use_field_names[$key] . '=NULL'; 487 } 488 else if ( in_array( $use_field_names[$key], $doNotEscapeFields ) ) 489 { 490 $field_text_entry = $use_field_names[$key] . "=" . $changedValueFields[$key]; 491 } 492 else 493 { 494 $field_text_entry = $use_field_names[$key] . "='" . $db->escapeString( $value ) . "'"; 495 } 496 497 $field_text_len += strlen( $field_text_entry ); 498 $needNewline = false; 499 if ( $field_text_len > 60 ) 500 { 501 $needNewline = true; 502 $field_text_len = 0; 503 } 504 if ( $i > 0 ) 505 $field_text .= "," . ($needNewline ? "\n " : ' '); 506 $field_text .= $field_text_entry; 507 ++$i; 508 } 509 $cond_text = eZPersistentObject::conditionText( $key_conds ); 510 $sql = "UPDATE $table\nSET $field_text$cond_text"; 511 $db->query( $sql ); 512 } 513 } 514 $obj->setHasDirtyData( false ); 515 } 516 517 /*! 518 Calls conditionTextByRow with an empty row and \a $conditions. 519 */ 520 function conditionText( &$conditions ) 521 { 522 $row = null; 523 return eZPersistentObject::conditionTextByRow( $conditions, $row ); 524 } 525 526 /*! 527 Generates an SQL sentence from the conditions \a $conditions and row data \a $row. 528 If \a $row is empty (null) it uses the condition data instead of row data. 529 */ 530 function &conditionTextByRow( &$conditions, &$row ) 531 { 532 $db =& eZDB::instance(); 533 534 $where_text = ""; 535 if ( is_array( $conditions ) and 536 count( $conditions ) > 0 ) 537 { 538 $where_text = "\nWHERE "; 539 $i = 0; 540 foreach ( $conditions as $id => $cond ) 541 { 542 if ( $i > 0 ) 543 $where_text .= " AND "; 544 if ( is_array( $row ) ) 545 { 546 $where_text .= $cond . "='" . $db->escapeString( $row[$cond] ) . "'"; 547 } 548 else 549 { 550 if ( is_array( $cond ) ) 551 { 552 if ( is_array( $cond[0] ) ) 553 { 554 $where_text .= $id . ' IN ( '; 555 $j = 0; 556 foreach ( $cond[0] as $value ) 557 { 558 if ( $j > 0 ) 559 $where_text .= ", "; 560 $where_text .= "'" . $db->escapeString( $value ) . "'"; 561 ++$j; 562 } 563 $where_text .= ' ) '; 564 } 565 else if ( is_array( $cond[1] ) ) 566 { 567 $range = $cond[1]; 568 $where_text .= "$id BETWEEN '" . $db->escapeString( $range[0] ) . "' AND '" . $db->escapeString( $range[1] ) . "'"; 569 } 570 else 571 { 572 switch ( $cond[0] ) 573 { 574 case '>=': 575 case '<=': 576 case '<': 577 case '>': 578 case '=': 579 case '<>': 580 case '!=': 581 case 'like': 582 { 583 $where_text .= $db->escapeString( $id ) . " " . $cond[0] . " '" . $db->escapeString( $cond[1] ) . "'"; 584 } break; 585 default: 586 { 587 eZDebug::writeError( "Conditional operator '$cond[0]' is not supported.",'eZPersistentObject::conditionTextByRow()' ); 588 } break; 589 } 590 591 } 592 } 593 else 594 $where_text .= $db->escapeString( $id ) . "='" . $db->escapeString( $cond ) . "'"; 595 } 596 ++$i; 597 } 598 } 599 return $where_text; 600 } 601 602 603 /*! 604 Creates an SQL query out of the different parameters and returns an array with the result. 605 If \a $asObject is true the array contains objects otherwise a db row. 606 607 608 \param $def A definition array of all fields, table name and sorting 609 \param $field_filters If defined determines the fields which are extracted (array of field names), if not all fields are fetched 610 \param $conds \c null for no special condition or an associative array of fields to filter on. 611 Syntax is \c FIELD => \c CONDITION, \c CONDITION can be one of: 612 - Scalar value - Creates a condition where \c FIELD must match the value, e.g 613 \code array( 'id' => 5 ) \endcode 614 generates SQL 615 \code id = 5 \endcode 616 - Array with two scalar values - Element \c 0 is the match operator and element \c 1 is the scalar value 617 \code array( 'priority' => array( '>', 5 ) ) \endcode 618 generates SQL 619 \code priority > 5 \endcode 620 - Array with range - Element \c 1 is an array with start and stop of range in array 621 \code array( 'type' => array( false, array( 1, 5 ) ) ) \endcode 622 generates SQL 623 \code type BETWEEN 1 AND 5 \endcode 624 - Array with multiple elements - Element \c 0 is an array with scalar values 625 \code array( 'id' => array( array( 1, 5, 7 ) ) ) \endcode 626 generates SQL 627 \code id IN ( 1, 5, 7 ) \endcode 628 \param $sorts An associative array of sorting conditions, if set to \c false ignores settings in \a $def, 629 if set to \c null uses settingss in \a $def. 630 Syntax is \c FIELD => \c DIRECTION. \c DIRECTION must either be string \c 'asc' 631 for ascending or \c 'desc' for descending. 632 \param $limit An associative array with limitiations, can contain 633 - offset - Numerical value defining the start offset for the fetch 634 - length - Numerical value defining the max number of items to return 635 \param $asObject If \c true then it will return an array with objects, objects are created from class defined in \a $def. 636 If \c false it will just return the rows fetch from database. 637 \param $grouping An array of fields to group by or \c null to use grouping in defintion \a $def. 638 \param $custom_fields Array of \c FIELD elements to add to SQL, can be used to perform custom fetches, e.g counts. 639 \c FIELD is an associative array containing: 640 - operation - A text field which is included in the field list 641 - name - If present it adds 'AS name' to the operation. 642 \param $custom_conds Array of ready sql conditions for 'WHERE' clause. 643 \param $custom_tables Array of additional tables. 644 645 A full example: 646 \code 647 $filter = array( 'id', 'name' ); 648 $conds = array( 'type' => 5, 649 'size' => array( false, array( 200, 500 ) ) ); 650 $sorts = array( 'name' => 'asc' ); 651 $limit = array( 'offset' => 50, 'length' => 10 ); 652 eZPersistentObject::fetchObjectList( $def, $filter, $conds, $sorts, $limit, true, false, null ) 653 \endcode 654 655 Counting number of elements. 656 \code 657 $custom = array( array( 'operation' => 'count( id )', 658 'name' => 'count' ) ); 659 // Here $field_filters is set to an empty array, that way only count is used in fields 660 $rows = eZPersistentObject::fetchObjectList( $def, array(), null, null, null, false, false, $custom ); 661 return $rows[0]['count']; 662 \endcode 663 664 Counting elements per type using grouping 665 \code 666 $custom = array( array( 'operation' => 'count( id )', 667 'name' => 'count' ) ); 668 $group = array( 'type' ); 669 $rows = eZPersistentObject::fetchObjectList( $def, array(), null, null, null, false, $group, $custom ); 670 return $rows[0]['count']; 671 \endcode 672 */ 673 function fetchObjectList( &$def, 674 $field_filters = null, 675 $conds = null, 676 $sorts = null, 677 $limit = null, 678 $asObject = true, 679 $grouping = false, 680 $custom_fields = null, 681 $custom_tables = null, 682 $custom_conds = null ) 683 { 684 $db =& eZDB::instance(); 685 $fields =& $def["fields"]; 686 $tables =& $def["name"]; 687 $class_name =& $def["class_name"]; 688 if ( is_array( $custom_tables ) ) 689 { 690 foreach( $custom_tables as $custom_table ) 691 $tables .= ', ' . $db->escapeString( $custom_table ); 692 } 693 eZPersistentObject::replaceFieldsWithShortNames( $db, $fields, $conds ); 694 if ( is_array( $field_filters ) ) 695 $field_array = array_unique( array_intersect( 696 $field_filters, array_keys( $fields ) ) ); 697 else 698 $field_array = array_keys( $fields ); 699 if ( $custom_fields !== null and is_array( $custom_fields ) ) 700 { 701 foreach( $custom_fields as $custom_field ) 702 { 703 if ( is_array( $custom_field ) ) 704 { 705 $custom_text = $custom_field["operation"]; 706 if ( isset( $custom_field["name"] ) ) 707 { 708 $field_name =& $custom_field["name"]; 709 $custom_text .= " AS $field_name"; 710 } 711 } 712 else 713 { 714 $custom_text = $custom_field; 715 } 716 $field_array[] = $custom_text; 717 } 718 } 719 eZPersistentObject::replaceFieldsWithShortNames( $db, $fields, $field_array ); 720 $field_text = ''; 721 $i = 0; 722 foreach ( $field_array as $field_item ) 723 { 724 if ( ( $i % 7 ) == 0 and 725 $i > 0 ) 726 $field_text .= ",\n "; 727 else if ( $i > 0 ) 728 $field_text .= ', '; 729 $field_text .= $field_item; 730 ++$i; 731 } 732 733 $where_text = eZPersistentObject::conditionText( $conds ); 734 if ( $custom_conds ) 735 $where_text .= $custom_conds; 736 737 $sort_text = ""; 738 if ( $sorts !== false and ( isset( $def["sort"] ) or is_array( $sorts ) ) ) 739 { 740 $sort_list =& $def["sort"]; 741 if ( is_array( $sorts ) ) 742 $sort_list =& $sorts; 743 if ( count( $sort_list ) > 0 ) 744 { 745 $sort_text = "\nORDER BY "; 746 $i = 0; 747 foreach ( $sort_list as $sort_id => $sort_type ) 748 { 749 if ( $i > 0 ) 750 $sort_text .= ", "; 751 if ( $sort_type == "desc" ) 752 $sort_text .= "$sort_id DESC"; 753 else 754 $sort_text .= "$sort_id ASC"; 755 ++$i; 756 } 757 } 758 } 759 760 $grouping_text = ""; 761 if ( isset( $def["grouping"] ) or ( is_array( $grouping ) and count( $grouping) > 0 ) ) 762 { 763 $grouping_list =& $def["grouping"]; 764 if ( is_array( $grouping ) ) 765 $grouping_list =& $grouping; 766 if ( count( $grouping_list ) > 0 ) 767 { 768 $grouping_text = "\nGROUP BY "; 769 $i = 0; 770 foreach ( $grouping_list as $grouping_id ) 771 { 772 if ( $i > 0 ) 773 $grouping_text .= ", "; 774 $grouping_text .= "$grouping_id"; 775 ++$i; 776 } 777 } 778 } 779 780 $db_params = array(); 781 if ( is_array( $limit ) ) 782 { 783 if ( isset( $limit["offset"] ) ) 784 { 785 $db_params["offset"] = $limit["offset"]; 786 } 787 if ( isset( $limit['limit'] ) ) 788 { 789 $db_params["limit"] = $limit["limit"]; 790 } 791 else 792 { 793 $db_params["limit"] = $limit["length"]; 794 } 795 } 796 797 $sqlText = "SELECT $field_text 798 FROM $tables" . 799 $where_text . 800 $grouping_text . 801 $sort_text; 802 $rows = $db->arrayQuery( $sqlText, 803 $db_params ); 804 805 // Indicate that a DB error occured. 806 if ( $rows === false ) 807 return null; 808 809 $objectList = eZPersistentObject::handleRows( $rows, $class_name, $asObject ); 810 return $objectList; 811 } 812 813 /*! 814 Creates PHP objects out of the database rows \a $rows. 815 Each object is created from class \$ class_name and is passed 816 as a row array as parameter. 817 818 \param $asObject If \c true then objects will be created, 819 if not it just returns \a $rows as it is. 820 */ 821 function handleRows( &$rows, $class_name, $asObject ) 822 { 823 if ( $asObject ) 824 { 825 $objects = array(); 826 if ( is_array( $rows ) ) 827 { 828 foreach ( $rows as $row ) 829 { 830 $objects[] = new $class_name( $row ); 831 } 832 } 833 return $objects; 834 } 835 else 836 return $rows; 837 } 838 839 /*! 840 Sets row id \a $id2 to have the placement of row id \a $id1. 841 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 842 the calls within a db transaction; thus within db->begin and db->commit. 843 */ 844 function swapRow( $table, &$keys, &$order_id, &$rows, $id1, $id2 ) 845 { 846 $db =& eZDB::instance(); 847 $text = $order_id . "='" . $db->escapeString( $rows[$id1][$order_id] ) . "' WHERE "; 848 $i = 0; 849 foreach ( $keys as $key ) 850 { 851 if ( $i > 0 ) 852 $text .= " AND "; 853 $text .= $key . "='" . $db->escapeString( $rows[$id2][$key] ) . "'"; 854 ++$i; 855 } 856 return "UPDATE $table SET $text"; 857 } 858 859 /*! 860 Returns an order value which can be used for new items in table, for instance placement. 861 Uses \a $def, \a $orderField and \a $conditions to figure out the currently maximum order value 862 and returns one that is larger. 863 */ 864 function newObjectOrder( &$def, $orderField, $conditions ) 865 { 866 $db =& eZDB::instance(); 867 $table =& $def["name"]; 868 $keys =& $def["keys"]; 869 $cond_text = eZPersistentObject::conditionText( $conditions ); 870 $rows = $db->arrayQuery( "SELECT MAX($orderField) AS $orderField FROM $table $cond_text" ); 871 if ( count( $rows ) > 0 and isset( $rows[0][$orderField] ) ) 872 return $rows[0][$orderField] + 1; 873 else 874 return 1; 875 } 876 877 /*! 878 Moves a row in a database table. \a $def is the object definition. 879 Uses \a $orderField to determine the order of objects in a table, usually this 880 is a placement of some kind. It uses this order field to figure out how move 881 the row, the row is either swapped with another row which is either above or 882 below according to whether \a $down is true or false, or it is swapped 883 with the first item or the last item depending on whether this row is first or last. 884 Uses \a $conditions to figure out unique rows. 885 \sa swapRow 886 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 887 the calls within a db transaction; thus within db->begin and db->commit. 888 */ 889 function reorderObject( &$def, 890 /*! Associative array with one element, the key is the order id and values is order value. */ 891 $orderField, 892 $conditions, 893 $down = true ) 894 { 895 $db =& eZDB::instance(); 896 $table =& $def["name"]; 897 $keys =& $def["keys"]; 898 899 reset( $orderField ); 900 $order_id = key( $orderField ); 901 $order_val = $orderField[$order_id]; 902 if ( $down ) 903 { 904 $order_operator = ">="; 905 $order_type = "asc"; 906 $order_add = -1; 907 } 908 else 909 { 910 $order_operator = "<="; 911 $order_type = "desc"; 912 $order_add = 1; 913 } 914 $fields = array_merge( $keys, array( $order_id ) ); 915 $rows = eZPersistentObject::fetchObjectList( $def, 916 $fields, 917 array_merge( $conditions, 918 array( $order_id => array( $order_operator, 919 $order_val ) ) ), 920 array( $order_id => $order_type ), 921 array( "length" => 2 ), 922 false ); 923 if ( count( $rows ) == 2 ) 924 { 925 $swapSQL1 = eZPersistentObject::swapRow( $table, $keys, $order_id, $rows, 1, 0 ); 926 $swapSQL2 = eZPersistentObject::swapRow( $table, $keys, $order_id, $rows, 0, 1 ); 927 $db->begin(); 928 $db->query( $swapSQL1 ); 929 $db->query( $swapSQL2 ); 930 $db->commit(); 931 } 932 else 933 { 934 $tmp = eZPersistentObject::fetchObjectList( $def, 935 $fields, 936 $conditions, 937 array( $order_id => $order_type ), 938 array( "length" => 1 ), 939 false ); 940 $where_text = eZPersistentObject::conditionTextByRow( $keys, $rows[0] ); 941 $db->query( "UPDATE $table SET $order_id='" . ( $tmp[0][$order_id] + $order_add ) . 942 "'$where_text" ); 943 } 944 } 945 946 /*! 947 \return the definition for the object, the default implementation 948 is to return an empty array. It's upto each inheriting class 949 to return a proper definition array. 950 951 The definition array is an associative array consists of these keys: 952 - fields - an associative array of fields which defines which database field (the key) is to fetched and how they map 953 to object member variables (the value). 954 - keys - an array of fields which is used for uniquely identifying the object in the table. 955 - function_attributes - an associative array of attributes which maps to member functions, used for fetching data with functions. 956 - set_functions - an associative array of attributes which maps to member functions, used for setting data with functions. 957 - increment_key - the field which is incremented on table inserts. 958 - class_name - the classname which is used for instantiating new objecs when fetching from the 959 database. 960 - sort - an associative array which defines the default sorting of lists, the key is the table field while the value 961 is the sorting method which is either \c asc or \c desc. 962 - name - the name of the database table 963 964 Example: 965 \code 966 function definition() 967 { 968 return array( "fields" => array( "id" => "ID", 969 "version" => "Version", 970 "name" => "Name" ), 971 "keys" => array( "id", "version" ), 972 "function_attributes" => array( "current" => "currentVersion", 973 "class_name" => "className" ), 974 "increment_key" => "id", 975 "class_name" => "eZContentClass", 976 "sort" => array( "id" => "asc" ), 977 "name" => "ezcontentclass" ); 978 } 979 \endcode 980 */ 981 function definition() 982 { 983 return array(); 984 } 985 986 function &escapeArray( &$array ) 987 { 988 $db =& eZDB::instance(); 989 $out = array(); 990 foreach( $array as $key => $value ) 991 { 992 if ( is_array( $value ) ) 993 { 994 $tmp = array(); 995 foreach( $value as $valueItem ) 996 { 997 $tmp[] = $db->escapeString( $valueItem ); 998 } 999 $out[$key] = $tmp; 1000 unset( $tmp ); 1001 } 1002 else 1003 $out[$key] = $db->escapeString( $value ); 1004 } 1005 return $out; 1006 } 1007 1008 /*! 1009 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 1010 the calls within a db transaction; thus within db->begin and db->commit. 1011 */ 1012 function updateObjectList( $parameters ) 1013 { 1014 $db =& eZDB::instance(); 1015 $def =& $parameters['definition']; 1016 $table =& $def['name']; 1017 $fields =& $def['fields']; 1018 $keys =& $def['keys']; 1019 1020 $updateFields =& $parameters['update_fields']; 1021 $conditions =& $parameters['conditions']; 1022 1023 $query = "UPDATE $table SET "; 1024 $i = 0; 1025 $valueBound = false; 1026 1027 foreach( $updateFields as $field => $value ) 1028 { 1029 $fieldDef =& $fields[ $field ]; 1030 $numericDataTypes = array( 'integer', 'float', 'double' ); 1031 if ( strlen( $value ) == 0 && 1032 is_array( $fieldDef ) && 1033 in_array( $fieldDef['datatype'], $numericDataTypes ) && 1034 array_key_exists( 'default', $fieldDef ) && 1035 !is_null( $fieldDef[ 'default' ] ) ) 1036 { 1037 $value=$fieldDef[ 'default' ]; 1038 } 1039 1040 $bindDataTypes = array( 'text' ); 1041 if ( $db->bindingType() != EZ_DB_BINDING_NO && 1042 strlen( $value ) > 2000 && 1043 is_array( $fieldDef ) && 1044 in_array( $fieldDef['datatype'], $bindDataTypes ) 1045 ) 1046 { 1047 $value = $db->bindVariable( $value, $fieldDef ); 1048 $valueBound = true; 1049 } 1050 else 1051 $valueBound = false; 1052 1053 if ( $i > 0 ) 1054 $query .= ', '; 1055 if ( $valueBound ) 1056 $query .= $field . "=" . $value; 1057 else 1058 $query .= $field . "='" . $db->escapeString( $value ) . "'"; 1059 ++$i; 1060 } 1061 $query .= "\n" . 'WHERE '; 1062 $i = 0; 1063 foreach( $conditions as $conditionKey => $condition ) 1064 { 1065 if ( $i > 0 ) 1066 $query .= ' AND '; 1067 if ( is_array( $condition ) ) 1068 { 1069 $query .= $conditionKey . ' IN ('; 1070 $j = 0; 1071 foreach( $condition as $conditionValue ) 1072 { 1073 if ( $j > 0 ) 1074 $query .= ', '; 1075 $query .= "'" . $db->escapeString( $conditionValue ) . "'"; 1076 ++$j; 1077 } 1078 $query .= ')'; 1079 } 1080 else 1081 $query .= $conditionKey . "='" . $db->escapeString( $condition ) . "'"; 1082 ++$i; 1083 } 1084 $db->query( $query ); 1085 } 1086 1087 /*! 1088 \return the attributes for this object, taken from the definition fields and 1089 function attributes. 1090 */ 1091 function attributes() 1092 { 1093 $def = $this->definition(); 1094 $attrs = array_keys( $def["fields"] ); 1095 if ( isset( $def["function_attributes"] ) ) 1096 $attrs = array_unique( array_merge( $attrs, array_keys( $def["function_attributes"] ) ) ); 1097 if ( isset( $def["functions"] ) ) 1098 $attrs = array_unique( array_merge( $attrs, array_keys( $def["functions"] ) ) ); 1099 return $attrs; 1100 } 1101 1102 /*! 1103 \return true if the attribute \a $attr is part of the definition fields or function attributes. 1104 */ 1105 function hasAttribute( $attr ) 1106 { 1107 $def = $this->definition(); 1108 $has_attr = isset( $def["fields"][$attr] ); 1109 if ( !$has_attr and isset( $def["function_attributes"] ) ) 1110 $has_attr = isset( $def["function_attributes"][$attr] ); 1111 if ( !$has_attr and isset( $def["functions"] ) ) 1112 $has_attr = isset( $def["functions"][$attr] ); 1113 return $has_attr; 1114 } 1115 1116 /*! 1117 \return the attribute data for \a $attr, this is either returned from the member variables 1118 or a member function depending on whether the definition field or function attributes matched. 1119 */ 1120 function &attribute( $attr, $noFunction = false ) 1121 { 1122 $def = $this->definition(); 1123 $fields =& $def["fields"]; 1124 $functions =& $def["functions"]; 1125 $attrFunctions =& $def["function_attributes"]; 1126 if ( $noFunction === false and isset( $attrFunctions[$attr] ) ) 1127 { 1128 $functionName = $attrFunctions[$attr]; 1129 $retVal = null; 1130 if ( method_exists( $this, $functionName ) ) 1131 { 1132 $retVal =& $this->$functionName(); 1133 } 1134 else 1135 { 1136 eZDebug::writeError( 'Could not find function : "' . get_class( $this ) . '::' . $functionName . '()".', 1137 'eZPersistentObject::attribute()' ); 1138 } 1139 return $retVal; 1140 } 1141 else if ( isset( $fields[$attr] ) ) 1142 { 1143 $attrName = $fields[$attr]; 1144 if ( is_array( $attrName ) ) 1145 { 1146 $attrName =& $attrName['name']; 1147 } 1148 return $this->$attrName; 1149 } 1150 else if ( isset( $functions[$attr] ) ) 1151 { 1152 $functionName = $functions[$attr]; 1153 return $this->$functionName(); 1154 } 1155 else 1156 { 1157 eZDebug::writeError( "Attribute '$attr' does not exist", $def['class_name'] . '::attribute' ); 1158 $attrValue = null; 1159 return $attrValue; 1160 } 1161 } 1162 1163 /*! 1164 Sets the attribute \a $attr to the value \a $val. The attribute must be present in the 1165 objects definition fields or set functions. 1166 */ 1167 function setAttribute( $attr, $val ) 1168 { 1169 $def = $this->definition(); 1170 $fields =& $def["fields"]; 1171 $functions =& $def["set_functions"]; 1172 if ( isset( $fields[$attr] ) ) 1173 { 1174 $attrName = $fields[$attr]; 1175 if ( is_array( $attrName ) ) 1176 { 1177 $attrName =& $attrName['name']; 1178 } 1179 1180 $oldValue = null; 1181 if ( isset( $this->$attrName ) ) 1182 $oldValue = $this->$attrName; 1183 $this->$attrName = $val; 1184 if ( $oldValue === null or $oldValue !== $val ) 1185 $this->setHasDirtyData( true ); 1186 } 1187 else if ( isset( $functions[$attr] ) ) 1188 { 1189 $functionName = $functions[$attr]; 1190 $oldValue = $this->$functionName( $val ); 1191 if ( $oldValue === null or $oldValue !== $val ) 1192 $this->setHasDirtyData( true ); 1193 } 1194 else 1195 { 1196 eZDebug::writeError( "Undefined attribute '$attr', cannot set", 1197 $def['class_name'] ); 1198 } 1199 } 1200 1201 /*! 1202 \return true if the data is considered dirty and needs to be stored. 1203 \sa sync 1204 */ 1205 function hasDirtyData() 1206 { 1207 return $this->PersistentDataDirty; 1208 } 1209 1210 /*! 1211 Sets whether the object has dirty data or not. 1212 \sa hasDirtyData, sync 1213 */ 1214 function setHasDirtyData( $hasDirtyData ) 1215 { 1216 $this->PersistentDataDirty = $hasDirtyData; 1217 } 1218 1219 /*! 1220 \return short attribute name (alias) if it's defined, given attribute name otherwise 1221 */ 1222 function getShortAttributeName( &$db, &$def, $attrName ) 1223 { 1224 $fields =& $def['fields']; 1225 1226 if ( $db->useShortNames() && isset( $fields[$attrName] ) && array_key_exists( 'short_name', $fields[$attrName] ) && $fields[$attrName]['short_name'] ) 1227 return $fields[$attrName]['short_name']; 1228 1229 return $attrName; 1230 } 1231 1232 /// \privatesection 1233 /// Whether the data is dirty, ie needs to be stored, or not. 1234 var $PersistentDataDirty; 1235 } 1236 1237 ?>
titre
Description
Corps
titre
Description
Corps
titre
Description
Corps
titre
Corps
| Généré le : Sat Feb 24 10:30:04 2007 | par Balluche grâce à PHPXref 0.7 |