MediaWiki
REL1_21
|
00001 <?php 00031 class ORMTable extends DBAccessBase implements IORMTable { 00032 00041 protected static $instanceCache = array(); 00042 00048 protected $tableName; 00049 00055 protected $fields = array(); 00056 00062 protected $fieldPrefix = ''; 00063 00069 protected $rowClass = 'ORMRow'; 00070 00076 protected $defaults = array(); 00077 00086 protected $readDb = DB_SLAVE; 00087 00099 public function __construct( $tableName = '', array $fields = array(), array $defaults = array(), $rowClass = null, $fieldPrefix = '' ) { 00100 $this->tableName = $tableName; 00101 $this->fields = $fields; 00102 $this->defaults = $defaults; 00103 00104 if ( is_string( $rowClass ) ) { 00105 $this->rowClass = $rowClass; 00106 } 00107 00108 $this->fieldPrefix = $fieldPrefix; 00109 } 00110 00119 public function getName() { 00120 if ( $this->tableName === '' ) { 00121 throw new MWException( 'The table name needs to be set' ); 00122 } 00123 00124 return $this->tableName; 00125 } 00126 00134 protected function getFieldPrefix() { 00135 return $this->fieldPrefix; 00136 } 00137 00145 public function getRowClass() { 00146 return $this->rowClass; 00147 } 00148 00157 public function getFields() { 00158 if ( $this->fields === array() ) { 00159 throw new MWException( 'The table needs to have one or more fields' ); 00160 } 00161 00162 return $this->fields; 00163 } 00164 00173 public function getDefaults() { 00174 return $this->defaults; 00175 } 00176 00186 public function getSummaryFields() { 00187 return array(); 00188 } 00189 00203 public function select( $fields = null, array $conditions = array(), 00204 array $options = array(), $functionName = null ) { 00205 $res = $this->rawSelect( $fields, $conditions, $options, $functionName ); 00206 return new ORMResult( $this, $res ); 00207 } 00208 00223 public function selectObjects( $fields = null, array $conditions = array(), 00224 array $options = array(), $functionName = null ) { 00225 $result = $this->selectFields( $fields, $conditions, $options, false, $functionName ); 00226 00227 $objects = array(); 00228 00229 foreach ( $result as $record ) { 00230 $objects[] = $this->newRow( $record ); 00231 } 00232 00233 return $objects; 00234 } 00235 00249 public function rawSelect( $fields = null, array $conditions = array(), 00250 array $options = array(), $functionName = null ) { 00251 if ( is_null( $fields ) ) { 00252 $fields = array_keys( $this->getFields() ); 00253 } 00254 else { 00255 $fields = (array)$fields; 00256 } 00257 00258 $dbr = $this->getReadDbConnection(); 00259 $result = $dbr->select( 00260 $this->getName(), 00261 $this->getPrefixedFields( $fields ), 00262 $this->getPrefixedValues( $conditions ), 00263 is_null( $functionName ) ? __METHOD__ : $functionName, 00264 $options 00265 ); 00266 00267 /* @var Exception $error */ 00268 $error = null; 00269 00270 if ( $result === false ) { 00271 // Database connection was in "ignoreErrors" mode. We don't like that. 00272 // So, we emulate the DBQueryError that should have been thrown. 00273 $error = new DBQueryError( 00274 $dbr, 00275 $dbr->lastError(), 00276 $dbr->lastErrno(), 00277 $dbr->lastQuery(), 00278 is_null( $functionName ) ? __METHOD__ : $functionName 00279 ); 00280 } 00281 00282 $this->releaseConnection( $dbr ); 00283 00284 if ( $error ) { 00285 // Note: construct the error before releasing the connection, 00286 // but throw it after. 00287 throw $error; 00288 } 00289 00290 return $result; 00291 } 00292 00315 public function selectFields( $fields = null, array $conditions = array(), 00316 array $options = array(), $collapse = true, $functionName = null ) { 00317 $objects = array(); 00318 00319 $result = $this->rawSelect( $fields, $conditions, $options, $functionName ); 00320 00321 foreach ( $result as $record ) { 00322 $objects[] = $this->getFieldsFromDBResult( $record ); 00323 } 00324 00325 if ( $collapse ) { 00326 if ( count( $fields ) === 1 ) { 00327 $objects = array_map( 'array_shift', $objects ); 00328 } 00329 elseif ( count( $fields ) === 2 ) { 00330 $o = array(); 00331 00332 foreach ( $objects as $object ) { 00333 $o[array_shift( $object )] = array_shift( $object ); 00334 } 00335 00336 $objects = $o; 00337 } 00338 } 00339 00340 return $objects; 00341 } 00342 00356 public function selectRow( $fields = null, array $conditions = array(), 00357 array $options = array(), $functionName = null ) { 00358 $options['LIMIT'] = 1; 00359 00360 $objects = $this->select( $fields, $conditions, $options, $functionName ); 00361 00362 return ( !$objects || $objects->isEmpty() ) ? false : $objects->current(); 00363 } 00364 00378 public function rawSelectRow( array $fields, array $conditions = array(), 00379 array $options = array(), $functionName = null ) { 00380 $dbr = $this->getReadDbConnection(); 00381 00382 $result = $dbr->selectRow( 00383 $this->getName(), 00384 $fields, 00385 $conditions, 00386 is_null( $functionName ) ? __METHOD__ : $functionName, 00387 $options 00388 ); 00389 00390 $this->releaseConnection( $dbr ); 00391 return $result; 00392 } 00393 00411 public function selectFieldsRow( $fields = null, array $conditions = array(), 00412 array $options = array(), $collapse = true, $functionName = null ) { 00413 $options['LIMIT'] = 1; 00414 00415 $objects = $this->selectFields( $fields, $conditions, $options, $collapse, $functionName ); 00416 00417 return empty( $objects ) ? false : $objects[0]; 00418 } 00419 00430 public function has( array $conditions = array() ) { 00431 return $this->selectRow( array( 'id' ), $conditions ) !== false; 00432 } 00433 00441 public function exists() { 00442 $dbr = $this->getReadDbConnection(); 00443 $exists = $dbr->tableExists( $this->getName() ); 00444 $this->releaseConnection( $dbr ); 00445 00446 return $exists; 00447 } 00448 00463 public function count( array $conditions = array(), array $options = array() ) { 00464 $res = $this->rawSelectRow( 00465 array( 'rowcount' => 'COUNT(*)' ), 00466 $this->getPrefixedValues( $conditions ), 00467 $options, 00468 __METHOD__ 00469 ); 00470 00471 return $res->rowcount; 00472 } 00473 00484 public function delete( array $conditions, $functionName = null ) { 00485 $dbw = $this->getWriteDbConnection(); 00486 00487 $result = $dbw->delete( 00488 $this->getName(), 00489 $conditions === array() ? '*' : $this->getPrefixedValues( $conditions ), 00490 is_null( $functionName ) ? __METHOD__ : $functionName 00491 ) !== false; // DatabaseBase::delete does not always return true for success as documented... 00492 00493 $this->releaseConnection( $dbw ); 00494 return $result; 00495 } 00496 00507 public function getAPIParams( $requireParams = false, $setDefaults = false ) { 00508 $typeMap = array( 00509 'id' => 'integer', 00510 'int' => 'integer', 00511 'float' => 'NULL', 00512 'str' => 'string', 00513 'bool' => 'integer', 00514 'array' => 'string', 00515 'blob' => 'string', 00516 ); 00517 00518 $params = array(); 00519 $defaults = $this->getDefaults(); 00520 00521 foreach ( $this->getFields() as $field => $type ) { 00522 if ( $field == 'id' ) { 00523 continue; 00524 } 00525 00526 $hasDefault = array_key_exists( $field, $defaults ); 00527 00528 $params[$field] = array( 00529 ApiBase::PARAM_TYPE => $typeMap[$type], 00530 ApiBase::PARAM_REQUIRED => $requireParams && !$hasDefault 00531 ); 00532 00533 if ( $type == 'array' ) { 00534 $params[$field][ApiBase::PARAM_ISMULTI] = true; 00535 } 00536 00537 if ( $setDefaults && $hasDefault ) { 00538 $default = is_array( $defaults[$field] ) ? implode( '|', $defaults[$field] ) : $defaults[$field]; 00539 $params[$field][ApiBase::PARAM_DFLT] = $default; 00540 } 00541 } 00542 00543 return $params; 00544 } 00545 00555 public function getFieldDescriptions() { 00556 return array(); 00557 } 00558 00566 public function getReadDb() { 00567 return $this->readDb; 00568 } 00569 00577 public function setReadDb( $db ) { 00578 $this->readDb = $db; 00579 } 00580 00588 public function getTargetWiki() { 00589 return $this->wiki; 00590 } 00591 00599 public function setTargetWiki( $wiki ) { 00600 $this->wiki = $wiki; 00601 } 00602 00613 public function getReadDbConnection() { 00614 return $this->getConnection( $this->getReadDb(), array() ); 00615 } 00616 00627 public function getWriteDbConnection() { 00628 return $this->getConnection( DB_MASTER, array() ); 00629 } 00630 00641 public function releaseConnection( DatabaseBase $db ) { 00642 parent::releaseConnection( $db ); // just make it public 00643 } 00644 00657 public function update( array $values, array $conditions = array() ) { 00658 $dbw = $this->getWriteDbConnection(); 00659 00660 $result = $dbw->update( 00661 $this->getName(), 00662 $this->getPrefixedValues( $values ), 00663 $this->getPrefixedValues( $conditions ), 00664 __METHOD__ 00665 ) !== false; // DatabaseBase::update does not always return true for success as documented... 00666 00667 $this->releaseConnection( $dbw ); 00668 return $result; 00669 } 00670 00679 public function updateSummaryFields( $summaryFields = null, array $conditions = array() ) { 00680 $slave = $this->getReadDb(); 00681 $this->setReadDb( DB_MASTER ); 00682 00686 foreach ( $this->select( null, $conditions ) as $item ) { 00687 $item->loadSummaryFields( $summaryFields ); 00688 $item->setSummaryMode( true ); 00689 $item->save(); 00690 } 00691 00692 $this->setReadDb( $slave ); 00693 } 00694 00706 public function getPrefixedValues( array $values ) { 00707 $prefixedValues = array(); 00708 00709 foreach ( $values as $field => $value ) { 00710 if ( is_integer( $field ) ) { 00711 if ( is_array( $value ) ) { 00712 $field = $value[0]; 00713 $value = $value[1]; 00714 } 00715 else { 00716 $value = explode( ' ', $value, 2 ); 00717 $value[0] = $this->getPrefixedField( $value[0] ); 00718 $prefixedValues[] = implode( ' ', $value ); 00719 continue; 00720 } 00721 } 00722 00723 $prefixedValues[$this->getPrefixedField( $field )] = $value; 00724 } 00725 00726 return $prefixedValues; 00727 } 00728 00739 public function getPrefixedFields( array $fields ) { 00740 foreach ( $fields as &$field ) { 00741 $field = $this->getPrefixedField( $field ); 00742 } 00743 00744 return $fields; 00745 } 00746 00756 public function getPrefixedField( $field ) { 00757 return $this->getFieldPrefix() . $field; 00758 } 00759 00769 public function unprefixFieldNames( array $fieldNames ) { 00770 return array_map( array( $this, 'unprefixFieldName' ), $fieldNames ); 00771 } 00772 00782 public function unprefixFieldName( $fieldName ) { 00783 return substr( $fieldName, strlen( $this->getFieldPrefix() ) ); 00784 } 00785 00794 public static function singleton() { 00795 $class = get_called_class(); 00796 00797 if ( !array_key_exists( $class, self::$instanceCache ) ) { 00798 self::$instanceCache[$class] = new $class; 00799 } 00800 00801 return self::$instanceCache[$class]; 00802 } 00803 00815 public function getFieldsFromDBResult( stdClass $result ) { 00816 $result = (array)$result; 00817 return array_combine( 00818 $this->unprefixFieldNames( array_keys( $result ) ), 00819 array_values( $result ) 00820 ); 00821 } 00822 00833 public function newFromDBResult( stdClass $result ) { 00834 return self::newRowFromDBResult( $result ); 00835 } 00836 00846 public function newRowFromDBResult( stdClass $result ) { 00847 return $this->newRow( $this->getFieldsFromDBResult( $result ) ); 00848 } 00849 00861 public function newFromArray( array $data, $loadDefaults = false ) { 00862 return static::newRow( $data, $loadDefaults ); 00863 } 00864 00875 public function newRow( array $data, $loadDefaults = false ) { 00876 $class = $this->getRowClass(); 00877 return new $class( $this, $data, $loadDefaults ); 00878 } 00879 00887 public function getFieldNames() { 00888 return array_keys( $this->getFields() ); 00889 } 00890 00900 public function canHaveField( $name ) { 00901 return array_key_exists( $name, $this->getFields() ); 00902 } 00903 00904 }