[ Index ]
 

Code source de eZ Publish 3.9.0

Accédez au Source d'autres logiciels libresSoutenez Angelica Josefina !

title

Body

[fermer]

/kernel/classes/ -> ezpersistentobject.php (source)

   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  ?>


Généré le : Sat Feb 24 10:30:04 2007 par Balluche grâce à PHPXref 0.7