r111591 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r111590‎ | r111591 | r111592 >
Date:22:56, 15 February 2012
Author:jeroendedauw
Status:ok
Tags:
Comment:
Move to EP untill slush ends
Modified paths:
  • /trunk/extensions/EducationProgram/includes/DBTable.php (added) (history)
  • /trunk/phase3/includes/DBTable.php (deleted) (history)

Diff [purge]

Index: trunk/extensions/EducationProgram/includes/DBTable.php
@@ -0,0 +1,651 @@
 2+<?php
 3+
 4+/**
 5+ * Abstract base class for representing a single database table.
 6+ *
 7+ * @since 1.20
 8+ *
 9+ * @file DBTable.php
 10+ *
 11+ * @licence GNU GPL v2 or later
 12+ * @author Jeroen De Dauw < jeroendedauw@gmail.com >
 13+ */
 14+abstract class DBTable {
 15+
 16+ /**
 17+ * Returns the name of the database table objects of this type are stored in.
 18+ *
 19+ * @since 1.20
 20+ *
 21+ * @return string
 22+ */
 23+ public abstract function getDBTable();
 24+
 25+ /**
 26+ * Returns the name of a DBDataObject deriving class that
 27+ * represents single rows in this table.
 28+ *
 29+ * @since 1.20
 30+ *
 31+ * @return string
 32+ */
 33+ public abstract function getDataObjectClass();
 34+
 35+ /**
 36+ * Gets the db field prefix.
 37+ *
 38+ * @since 1.20
 39+ *
 40+ * @return string
 41+ */
 42+ protected abstract function getFieldPrefix();
 43+
 44+ /**
 45+ * Returns an array with the fields and their types this object contains.
 46+ * This corresponds directly to the fields in the database, without prefix.
 47+ *
 48+ * field name => type
 49+ *
 50+ * Allowed types:
 51+ * * id
 52+ * * str
 53+ * * int
 54+ * * float
 55+ * * bool
 56+ * * array
 57+ *
 58+ * @since 1.20
 59+ *
 60+ * @return array
 61+ */
 62+ public abstract function getFieldTypes();
 63+
 64+ /**
 65+ * The database connection to use for read operations.
 66+ * Can be changed via @see setReadDb.
 67+ *
 68+ * @since 1.20
 69+ * @var integer DB_ enum
 70+ */
 71+ protected $readDb = DB_SLAVE;
 72+
 73+ /**
 74+ * Returns a list of default field values.
 75+ * field name => field value
 76+ *
 77+ * @since 1.20
 78+ *
 79+ * @return array
 80+ */
 81+ public function getDefaults() {
 82+ return array();
 83+ }
 84+
 85+ /**
 86+ * Returns a list of the summary fields.
 87+ * These are fields that cache computed values, such as the amount of linked objects of $type.
 88+ * This is relevant as one might not want to do actions such as log changes when these get updated.
 89+ *
 90+ * @since 1.20
 91+ *
 92+ * @return array
 93+ */
 94+ public function getSummaryFields() {
 95+ return array();
 96+ }
 97+
 98+ /**
 99+ * Selects the the specified fields of the records matching the provided
 100+ * conditions and returns them as DBDataObject. Field names get prefixed.
 101+ *
 102+ * @since 1.20
 103+ *
 104+ * @param array|string|null $fields
 105+ * @param array $conditions
 106+ * @param array $options
 107+ *
 108+ * @return array of self
 109+ */
 110+ public function select( $fields = null, array $conditions = array(), array $options = array() ) {
 111+ $result = $this->selectFields( $fields, $conditions, $options, false );
 112+
 113+ $objects = array();
 114+
 115+ foreach ( $result as $record ) {
 116+ $objects[] = $this->newFromArray( $record );
 117+ }
 118+
 119+ return $objects;
 120+ }
 121+
 122+ /**
 123+ * Selects the the specified fields of the records matching the provided
 124+ * conditions and returns them as associative arrays.
 125+ * Provided field names get prefixed.
 126+ * Returned field names will not have a prefix.
 127+ *
 128+ * When $collapse is true:
 129+ * If one field is selected, each item in the result array will be this field.
 130+ * If two fields are selected, each item in the result array will have as key
 131+ * the first field and as value the second field.
 132+ * If more then two fields are selected, each item will be an associative array.
 133+ *
 134+ * @since 1.20
 135+ *
 136+ * @param array|string|null $fields
 137+ * @param array $conditions
 138+ * @param array $options
 139+ * @param boolean $collapse Set to false to always return each result row as associative array.
 140+ *
 141+ * @return array of array
 142+ */
 143+ public function selectFields( $fields = null, array $conditions = array(), array $options = array(), $collapse = true ) {
 144+ if ( is_null( $fields ) ) {
 145+ $fields = array_keys( $this->getFieldTypes() );
 146+ }
 147+ else {
 148+ $fields = (array)$fields;
 149+ }
 150+
 151+ $dbr = wfGetDB( $this->getReadDb() );
 152+ $result = $dbr->select(
 153+ $this->getDBTable(),
 154+ $this->getPrefixedFields( $fields ),
 155+ $this->getPrefixedValues( $conditions ),
 156+ __METHOD__,
 157+ $options
 158+ );
 159+
 160+ $objects = array();
 161+
 162+ foreach ( $result as $record ) {
 163+ $objects[] = $this->getFieldsFromDBResult( $record );
 164+ }
 165+
 166+ if ( $collapse ) {
 167+ if ( count( $fields ) === 1 ) {
 168+ $objects = array_map( 'array_shift', $objects );
 169+ }
 170+ elseif ( count( $fields ) === 2 ) {
 171+ $o = array();
 172+
 173+ foreach ( $objects as $object ) {
 174+ $o[array_shift( $object )] = array_shift( $object );
 175+ }
 176+
 177+ $objects = $o;
 178+ }
 179+ }
 180+
 181+ return $objects;
 182+ }
 183+
 184+ /**
 185+ * Selects the the specified fields of the first matching record.
 186+ * Field names get prefixed.
 187+ *
 188+ * @since 1.20
 189+ *
 190+ * @param array|string|null $fields
 191+ * @param array $conditions
 192+ * @param array $options
 193+ *
 194+ * @return DBObject|bool False on failure
 195+ */
 196+ public function selectRow( $fields = null, array $conditions = array(), array $options = array() ) {
 197+ $options['LIMIT'] = 1;
 198+
 199+ $objects = $this->select( $fields, $conditions, $options );
 200+
 201+ return count( $objects ) > 0 ? $objects[0] : false;
 202+ }
 203+
 204+ /**
 205+ * Selects the the specified fields of the records matching the provided
 206+ * conditions. Field names do NOT get prefixed.
 207+ *
 208+ * @since 1.20
 209+ *
 210+ * @param array $fields
 211+ * @param array $conditions
 212+ * @param array $options
 213+ *
 214+ * @return ResultWrapper
 215+ */
 216+ public function rawSelectRow( array $fields, array $conditions = array(), array $options = array() ) {
 217+ $dbr = wfGetDB( $this->getReadDb() );
 218+
 219+ return $dbr->selectRow(
 220+ $this->getDBTable(),
 221+ $fields,
 222+ $conditions,
 223+ __METHOD__,
 224+ $options
 225+ );
 226+ }
 227+
 228+ /**
 229+ * Selects the the specified fields of the first record matching the provided
 230+ * conditions and returns it as an associative array, or false when nothing matches.
 231+ * This method makes use of selectFields and expects the same parameters and
 232+ * returns the same results (if there are any, if there are none, this method returns false).
 233+ * @see DBDataObject::selectFields
 234+ *
 235+ * @since 1.20
 236+ *
 237+ * @param array|string|null $fields
 238+ * @param array $conditions
 239+ * @param array $options
 240+ * @param boolean $collapse Set to false to always return each result row as associative array.
 241+ *
 242+ * @return mixed|array|bool False on failure
 243+ */
 244+ public function selectFieldsRow( $fields = null, array $conditions = array(), array $options = array(), $collapse = true ) {
 245+ $options['LIMIT'] = 1;
 246+
 247+ $objects = $this->selectFields( $fields, $conditions, $options, $collapse );
 248+
 249+ return count( $objects ) > 0 ? $objects[0] : false;
 250+ }
 251+
 252+ /**
 253+ * Returns if there is at least one record matching the provided conditions.
 254+ * Condition field names get prefixed.
 255+ *
 256+ * @since 1.20
 257+ *
 258+ * @param array $conditions
 259+ *
 260+ * @return boolean
 261+ */
 262+ public function has( array $conditions = array() ) {
 263+ return $this->selectRow( array( 'id' ), $conditions ) !== false;
 264+ }
 265+
 266+ /**
 267+ * Returns the amount of matching records.
 268+ * Condition field names get prefixed.
 269+ *
 270+ * Note that this can be expensive on large tables.
 271+ * In such cases you might want to use DatabaseBase::estimateRowCount instead.
 272+ *
 273+ * @since 1.20
 274+ *
 275+ * @param array $conditions
 276+ * @param array $options
 277+ *
 278+ * @return integer
 279+ */
 280+ public function count( array $conditions = array(), array $options = array() ) {
 281+ $res = $this->rawSelectRow(
 282+ array( 'COUNT(*) AS rowcount' ),
 283+ $this->getPrefixedValues( $conditions ),
 284+ $options
 285+ );
 286+
 287+ return $res->rowcount;
 288+ }
 289+
 290+ /**
 291+ * Removes the object from the database.
 292+ *
 293+ * @since 1.20
 294+ *
 295+ * @param array $conditions
 296+ *
 297+ * @return boolean Success indicator
 298+ */
 299+ public function delete( array $conditions ) {
 300+ return wfGetDB( DB_MASTER )->delete(
 301+ $this->getDBTable(),
 302+ $this->getPrefixedValues( $conditions )
 303+ );
 304+ }
 305+
 306+ /**
 307+ * Get API parameters for the fields supported by this object.
 308+ *
 309+ * @since 1.20
 310+ *
 311+ * @param boolean $requireParams
 312+ * @param boolean $setDefaults
 313+ *
 314+ * @return array
 315+ */
 316+ public function getAPIParams( $requireParams = false, $setDefaults = false ) {
 317+ $typeMap = array(
 318+ 'id' => 'integer',
 319+ 'int' => 'integer',
 320+ 'float' => 'NULL',
 321+ 'str' => 'string',
 322+ 'bool' => 'integer',
 323+ 'array' => 'string',
 324+ 'blob' => 'string',
 325+ );
 326+
 327+ $params = array();
 328+ $defaults = $this->getDefaults();
 329+
 330+ foreach ( $this->getFieldTypes() as $field => $type ) {
 331+ if ( $field == 'id' ) {
 332+ continue;
 333+ }
 334+
 335+ $hasDefault = array_key_exists( $field, $defaults );
 336+
 337+ $params[$field] = array(
 338+ ApiBase::PARAM_TYPE => $typeMap[$type],
 339+ ApiBase::PARAM_REQUIRED => $requireParams && !$hasDefault
 340+ );
 341+
 342+ if ( $type == 'array' ) {
 343+ $params[$field][ApiBase::PARAM_ISMULTI] = true;
 344+ }
 345+
 346+ if ( $setDefaults && $hasDefault ) {
 347+ $default = is_array( $defaults[$field] ) ? implode( '|', $defaults[$field] ) : $defaults[$field];
 348+ $params[$field][ApiBase::PARAM_DFLT] = $default;
 349+ }
 350+ }
 351+
 352+ return $params;
 353+ }
 354+
 355+ /**
 356+ * Returns an array with the fields and their descriptions.
 357+ *
 358+ * field name => field description
 359+ *
 360+ * @since 1.20
 361+ *
 362+ * @return array
 363+ */
 364+ public function getFieldDescriptions() {
 365+ return array();
 366+ }
 367+
 368+ /**
 369+ * Get the database type used for read operations.
 370+ *
 371+ * @since 1.20
 372+ *
 373+ * @return integer DB_ enum
 374+ */
 375+ public function getReadDb() {
 376+ return $this->readDb;
 377+ }
 378+
 379+ /**
 380+ * Set the database type to use for read operations.
 381+ *
 382+ * @param integer $db
 383+ *
 384+ * @since 1.20
 385+ */
 386+ public function setReadDb( $db ) {
 387+ $this->readDb = $db;
 388+ }
 389+
 390+ /**
 391+ * Update the records matching the provided conditions by
 392+ * setting the fields that are keys in the $values param to
 393+ * their corresponding values.
 394+ *
 395+ * @since 1.20
 396+ *
 397+ * @param array $values
 398+ * @param array $conditions
 399+ *
 400+ * @return boolean Success indicator
 401+ */
 402+ public function update( array $values, array $conditions = array() ) {
 403+ $dbw = wfGetDB( DB_MASTER );
 404+
 405+ return $dbw->update(
 406+ $this->getDBTable(),
 407+ $this->getPrefixedValues( $values ),
 408+ $this->getPrefixedValues( $conditions ),
 409+ __METHOD__
 410+ );
 411+ }
 412+
 413+ /**
 414+ * Computes the values of the summary fields of the objects matching the provided conditions.
 415+ *
 416+ * @since 1.20
 417+ *
 418+ * @param array|string|null $summaryFields
 419+ * @param array $conditions
 420+ */
 421+ public function updateSummaryFields( $summaryFields = null, array $conditions = array() ) {
 422+ $this->setReadDb( DB_MASTER );
 423+
 424+ foreach ( $this->select( null, $conditions ) as /* DBDataObject */ $item ) {
 425+ $item->loadSummaryFields( $summaryFields );
 426+ $item->setSummaryMode( true );
 427+ $item->save();
 428+ }
 429+
 430+ $this->setReadDb( DB_SLAVE );
 431+ }
 432+
 433+ /**
 434+ * Takes in an associative array with field names as keys and
 435+ * their values as value. The field names are prefixed with the
 436+ * db field prefix.
 437+ *
 438+ * Field names can also be provided as an array with as first element a table name, such as
 439+ * $conditions = array(
 440+ * array( array( 'tablename', 'fieldname' ), $value ),
 441+ * );
 442+ *
 443+ * @since 1.20
 444+ *
 445+ * @param array $values
 446+ *
 447+ * @return array
 448+ */
 449+ public function getPrefixedValues( array $values ) {
 450+ $prefixedValues = array();
 451+
 452+ foreach ( $values as $field => $value ) {
 453+ if ( is_integer( $field ) ) {
 454+ if ( is_array( $value ) ) {
 455+ $field = $value[0];
 456+ $value = $value[1];
 457+ }
 458+ else {
 459+ $value = explode( ' ', $value, 2 );
 460+ $value[0] = $this->getPrefixedField( $value[0] );
 461+ $prefixedValues[] = implode( ' ', $value );
 462+ continue;
 463+ }
 464+ }
 465+
 466+ $prefixedValues[$this->getPrefixedField( $field )] = $value;
 467+ }
 468+
 469+ return $prefixedValues;
 470+ }
 471+
 472+ /**
 473+ * Takes in a field or array of fields and returns an
 474+ * array with their prefixed versions, ready for db usage.
 475+ *
 476+ * @since 1.20
 477+ *
 478+ * @param array|string $fields
 479+ *
 480+ * @return array
 481+ */
 482+ public function getPrefixedFields( array $fields ) {
 483+ foreach ( $fields as &$field ) {
 484+ $field = $this->getPrefixedField( $field );
 485+ }
 486+
 487+ return $fields;
 488+ }
 489+
 490+ /**
 491+ * Takes in a field and returns an it's prefixed version, ready for db usage.
 492+ *
 493+ * @since 1.20
 494+ *
 495+ * @param string|array $field
 496+ *
 497+ * @return string
 498+ */
 499+ public function getPrefixedField( $field ) {
 500+ return $this->getFieldPrefix() . $field;
 501+ }
 502+
 503+ /**
 504+ * Takes an array of field names with prefix and returns the unprefixed equivalent.
 505+ *
 506+ * @since 1.20
 507+ *
 508+ * @param array $fieldNames
 509+ *
 510+ * @return array
 511+ */
 512+ public function unprefixFieldNames( array $fieldNames ) {
 513+ return array_map( array( $this, 'unprefixFieldName' ), $fieldNames );
 514+ }
 515+
 516+ /**
 517+ * Takes a field name with prefix and returns the unprefixed equivalent.
 518+ *
 519+ * @since 1.20
 520+ *
 521+ * @param string $fieldName
 522+ *
 523+ * @return string
 524+ */
 525+ public function unprefixFieldName( $fieldName ) {
 526+ return substr( $fieldName, strlen( $this->getFieldPrefix() ) );
 527+ }
 528+
 529+ public function __construct() {
 530+
 531+ }
 532+
 533+ /**
 534+ * Get an instance of this class.
 535+ *
 536+ * @since 1.20
 537+ *
 538+ * @return DBtable
 539+ */
 540+ public static function singleton() {
 541+ static $instance;
 542+
 543+ if ( !isset( $instance ) ) {
 544+ $class = function_exists( 'get_called_class' ) ? get_called_class() : self::get_called_class();
 545+ $instance = new $class;
 546+ }
 547+
 548+ return $instance;
 549+ }
 550+
 551+ /**
 552+ * Compatibility fallback function so the singleton method works on PHP < 5.3.
 553+ * Code borrowed from http://www.php.net/manual/en/function.get-called-class.php#107445
 554+ *
 555+ * @since 1.20
 556+ *
 557+ * @return string
 558+ */
 559+ protected static function get_called_class() {
 560+ $bt = debug_backtrace();
 561+ $l = count($bt) - 1;
 562+ $matches = array();
 563+ while(empty($matches) && $l > -1){
 564+ $lines = file($bt[$l]['file']);
 565+ $callerLine = $lines[$bt[$l]['line']-1];
 566+ preg_match('/([a-zA-Z0-9\_]+)::'.$bt[$l--]['function'].'/',
 567+ $callerLine,
 568+ $matches);
 569+ }
 570+ if (!isset($matches[1])) $matches[1]=NULL; //for notices
 571+ if ($matches[1] == 'self') {
 572+ $line = $bt[$l]['line']-1;
 573+ while ($line > 0 && strpos($lines[$line], 'class') === false) {
 574+ $line--;
 575+ }
 576+ preg_match('/class[\s]+(.+?)[\s]+/si', $lines[$line], $matches);
 577+ }
 578+ return $matches[1];
 579+ }
 580+
 581+ /**
 582+ * Get an array with fields from a database result,
 583+ * that can be fed directly to the constructor or
 584+ * to setFields.
 585+ *
 586+ * @since 1.20
 587+ *
 588+ * @param stdClass $result
 589+ *
 590+ * @return array
 591+ */
 592+ public function getFieldsFromDBResult( stdClass $result ) {
 593+ $result = (array)$result;
 594+ return array_combine(
 595+ $this->unprefixFieldNames( array_keys( $result ) ),
 596+ array_values( $result )
 597+ );
 598+ }
 599+
 600+ /**
 601+ * Get a new instance of the class from a database result.
 602+ *
 603+ * @since 1.20
 604+ *
 605+ * @param stdClass $result
 606+ *
 607+ * @return DBDataObject
 608+ */
 609+ public function newFromDBResult( stdClass $result ) {
 610+ return $this->newFromArray( $this->getFieldsFromDBResult( $result ) );
 611+ }
 612+
 613+ /**
 614+ * Get a new instance of the class from an array.
 615+ *
 616+ * @since 1.20
 617+ *
 618+ * @param array $data
 619+ * @param boolean $loadDefaults
 620+ *
 621+ * @return DBDataObject
 622+ */
 623+ public function newFromArray( array $data, $loadDefaults = false ) {
 624+ $class = $this->getDataObjectClass();
 625+ return new $class( $this, $data, $loadDefaults );
 626+ }
 627+
 628+ /**
 629+ * Return the names of the fields.
 630+ *
 631+ * @since 1.20
 632+ *
 633+ * @return array
 634+ */
 635+ public function getFieldNames() {
 636+ return array_keys( $this->getFieldTypes() );
 637+ }
 638+
 639+ /**
 640+ * Gets if the object can take a certain field.
 641+ *
 642+ * @since 1.20
 643+ *
 644+ * @param string $name
 645+ *
 646+ * @return boolean
 647+ */
 648+ public function canHaveField( $name ) {
 649+ return array_key_exists( $name, $this->getFieldTypes() );
 650+ }
 651+
 652+}
Property changes on: trunk/extensions/EducationProgram/includes/DBTable.php
___________________________________________________________________
Added: svn:mergeinfo
1653 Merged /branches/new-installer/phase3/includes/DBTable.php:r43664-66004
2654 Merged /branches/wmf-deployment/includes/DBTable.php:r53381
3655 Merged /branches/JSTesting/includes/DBTable.php:r100352-107913
4656 Merged /branches/REL1_15/phase3/includes/DBTable.php:r51646
5657 Merged /branches/wmf/1.18wmf1/includes/DBTable.php:r97508
6658 Merged /branches/sqlite/includes/DBTable.php:r58211-58321
Added: svn:eol-style
7659 + native
Index: trunk/phase3/includes/DBTable.php
@@ -1,651 +0,0 @@
2 -<?php
3 -
4 -/**
5 - * Abstract base class for representing a single database table.
6 - *
7 - * @since 1.20
8 - *
9 - * @file DBTable.php
10 - *
11 - * @licence GNU GPL v2 or later
12 - * @author Jeroen De Dauw < jeroendedauw@gmail.com >
13 - */
14 -abstract class DBTable {
15 -
16 - /**
17 - * Returns the name of the database table objects of this type are stored in.
18 - *
19 - * @since 1.20
20 - *
21 - * @return string
22 - */
23 - public abstract function getDBTable();
24 -
25 - /**
26 - * Returns the name of a DBDataObject deriving class that
27 - * represents single rows in this table.
28 - *
29 - * @since 1.20
30 - *
31 - * @return string
32 - */
33 - public abstract function getDataObjectClass();
34 -
35 - /**
36 - * Gets the db field prefix.
37 - *
38 - * @since 1.20
39 - *
40 - * @return string
41 - */
42 - protected abstract function getFieldPrefix();
43 -
44 - /**
45 - * Returns an array with the fields and their types this object contains.
46 - * This corresponds directly to the fields in the database, without prefix.
47 - *
48 - * field name => type
49 - *
50 - * Allowed types:
51 - * * id
52 - * * str
53 - * * int
54 - * * float
55 - * * bool
56 - * * array
57 - *
58 - * @since 1.20
59 - *
60 - * @return array
61 - */
62 - public abstract function getFieldTypes();
63 -
64 - /**
65 - * The database connection to use for read operations.
66 - * Can be changed via @see setReadDb.
67 - *
68 - * @since 1.20
69 - * @var integer DB_ enum
70 - */
71 - protected $readDb = DB_SLAVE;
72 -
73 - /**
74 - * Returns a list of default field values.
75 - * field name => field value
76 - *
77 - * @since 1.20
78 - *
79 - * @return array
80 - */
81 - public function getDefaults() {
82 - return array();
83 - }
84 -
85 - /**
86 - * Returns a list of the summary fields.
87 - * These are fields that cache computed values, such as the amount of linked objects of $type.
88 - * This is relevant as one might not want to do actions such as log changes when these get updated.
89 - *
90 - * @since 1.20
91 - *
92 - * @return array
93 - */
94 - public function getSummaryFields() {
95 - return array();
96 - }
97 -
98 - /**
99 - * Selects the the specified fields of the records matching the provided
100 - * conditions and returns them as DBDataObject. Field names get prefixed.
101 - *
102 - * @since 1.20
103 - *
104 - * @param array|string|null $fields
105 - * @param array $conditions
106 - * @param array $options
107 - *
108 - * @return array of self
109 - */
110 - public function select( $fields = null, array $conditions = array(), array $options = array() ) {
111 - $result = $this->selectFields( $fields, $conditions, $options, false );
112 -
113 - $objects = array();
114 -
115 - foreach ( $result as $record ) {
116 - $objects[] = $this->newFromArray( $record );
117 - }
118 -
119 - return $objects;
120 - }
121 -
122 - /**
123 - * Selects the the specified fields of the records matching the provided
124 - * conditions and returns them as associative arrays.
125 - * Provided field names get prefixed.
126 - * Returned field names will not have a prefix.
127 - *
128 - * When $collapse is true:
129 - * If one field is selected, each item in the result array will be this field.
130 - * If two fields are selected, each item in the result array will have as key
131 - * the first field and as value the second field.
132 - * If more then two fields are selected, each item will be an associative array.
133 - *
134 - * @since 1.20
135 - *
136 - * @param array|string|null $fields
137 - * @param array $conditions
138 - * @param array $options
139 - * @param boolean $collapse Set to false to always return each result row as associative array.
140 - *
141 - * @return array of array
142 - */
143 - public function selectFields( $fields = null, array $conditions = array(), array $options = array(), $collapse = true ) {
144 - if ( is_null( $fields ) ) {
145 - $fields = array_keys( $this->getFieldTypes() );
146 - }
147 - else {
148 - $fields = (array)$fields;
149 - }
150 -
151 - $dbr = wfGetDB( $this->getReadDb() );
152 - $result = $dbr->select(
153 - $this->getDBTable(),
154 - $this->getPrefixedFields( $fields ),
155 - $this->getPrefixedValues( $conditions ),
156 - __METHOD__,
157 - $options
158 - );
159 -
160 - $objects = array();
161 -
162 - foreach ( $result as $record ) {
163 - $objects[] = $this->getFieldsFromDBResult( $record );
164 - }
165 -
166 - if ( $collapse ) {
167 - if ( count( $fields ) === 1 ) {
168 - $objects = array_map( 'array_shift', $objects );
169 - }
170 - elseif ( count( $fields ) === 2 ) {
171 - $o = array();
172 -
173 - foreach ( $objects as $object ) {
174 - $o[array_shift( $object )] = array_shift( $object );
175 - }
176 -
177 - $objects = $o;
178 - }
179 - }
180 -
181 - return $objects;
182 - }
183 -
184 - /**
185 - * Selects the the specified fields of the first matching record.
186 - * Field names get prefixed.
187 - *
188 - * @since 1.20
189 - *
190 - * @param array|string|null $fields
191 - * @param array $conditions
192 - * @param array $options
193 - *
194 - * @return DBObject|bool False on failure
195 - */
196 - public function selectRow( $fields = null, array $conditions = array(), array $options = array() ) {
197 - $options['LIMIT'] = 1;
198 -
199 - $objects = $this->select( $fields, $conditions, $options );
200 -
201 - return count( $objects ) > 0 ? $objects[0] : false;
202 - }
203 -
204 - /**
205 - * Selects the the specified fields of the records matching the provided
206 - * conditions. Field names do NOT get prefixed.
207 - *
208 - * @since 1.20
209 - *
210 - * @param array $fields
211 - * @param array $conditions
212 - * @param array $options
213 - *
214 - * @return ResultWrapper
215 - */
216 - public function rawSelectRow( array $fields, array $conditions = array(), array $options = array() ) {
217 - $dbr = wfGetDB( $this->getReadDb() );
218 -
219 - return $dbr->selectRow(
220 - $this->getDBTable(),
221 - $fields,
222 - $conditions,
223 - __METHOD__,
224 - $options
225 - );
226 - }
227 -
228 - /**
229 - * Selects the the specified fields of the first record matching the provided
230 - * conditions and returns it as an associative array, or false when nothing matches.
231 - * This method makes use of selectFields and expects the same parameters and
232 - * returns the same results (if there are any, if there are none, this method returns false).
233 - * @see DBDataObject::selectFields
234 - *
235 - * @since 1.20
236 - *
237 - * @param array|string|null $fields
238 - * @param array $conditions
239 - * @param array $options
240 - * @param boolean $collapse Set to false to always return each result row as associative array.
241 - *
242 - * @return mixed|array|bool False on failure
243 - */
244 - public function selectFieldsRow( $fields = null, array $conditions = array(), array $options = array(), $collapse = true ) {
245 - $options['LIMIT'] = 1;
246 -
247 - $objects = $this->selectFields( $fields, $conditions, $options, $collapse );
248 -
249 - return count( $objects ) > 0 ? $objects[0] : false;
250 - }
251 -
252 - /**
253 - * Returns if there is at least one record matching the provided conditions.
254 - * Condition field names get prefixed.
255 - *
256 - * @since 1.20
257 - *
258 - * @param array $conditions
259 - *
260 - * @return boolean
261 - */
262 - public function has( array $conditions = array() ) {
263 - return $this->selectRow( array( 'id' ), $conditions ) !== false;
264 - }
265 -
266 - /**
267 - * Returns the amount of matching records.
268 - * Condition field names get prefixed.
269 - *
270 - * Note that this can be expensive on large tables.
271 - * In such cases you might want to use DatabaseBase::estimateRowCount instead.
272 - *
273 - * @since 1.20
274 - *
275 - * @param array $conditions
276 - * @param array $options
277 - *
278 - * @return integer
279 - */
280 - public function count( array $conditions = array(), array $options = array() ) {
281 - $res = $this->rawSelectRow(
282 - array( 'COUNT(*) AS rowcount' ),
283 - $this->getPrefixedValues( $conditions ),
284 - $options
285 - );
286 -
287 - return $res->rowcount;
288 - }
289 -
290 - /**
291 - * Removes the object from the database.
292 - *
293 - * @since 1.20
294 - *
295 - * @param array $conditions
296 - *
297 - * @return boolean Success indicator
298 - */
299 - public function delete( array $conditions ) {
300 - return wfGetDB( DB_MASTER )->delete(
301 - $this->getDBTable(),
302 - $this->getPrefixedValues( $conditions )
303 - );
304 - }
305 -
306 - /**
307 - * Get API parameters for the fields supported by this object.
308 - *
309 - * @since 1.20
310 - *
311 - * @param boolean $requireParams
312 - * @param boolean $setDefaults
313 - *
314 - * @return array
315 - */
316 - public function getAPIParams( $requireParams = false, $setDefaults = false ) {
317 - $typeMap = array(
318 - 'id' => 'integer',
319 - 'int' => 'integer',
320 - 'float' => 'NULL',
321 - 'str' => 'string',
322 - 'bool' => 'integer',
323 - 'array' => 'string',
324 - 'blob' => 'string',
325 - );
326 -
327 - $params = array();
328 - $defaults = $this->getDefaults();
329 -
330 - foreach ( $this->getFieldTypes() as $field => $type ) {
331 - if ( $field == 'id' ) {
332 - continue;
333 - }
334 -
335 - $hasDefault = array_key_exists( $field, $defaults );
336 -
337 - $params[$field] = array(
338 - ApiBase::PARAM_TYPE => $typeMap[$type],
339 - ApiBase::PARAM_REQUIRED => $requireParams && !$hasDefault
340 - );
341 -
342 - if ( $type == 'array' ) {
343 - $params[$field][ApiBase::PARAM_ISMULTI] = true;
344 - }
345 -
346 - if ( $setDefaults && $hasDefault ) {
347 - $default = is_array( $defaults[$field] ) ? implode( '|', $defaults[$field] ) : $defaults[$field];
348 - $params[$field][ApiBase::PARAM_DFLT] = $default;
349 - }
350 - }
351 -
352 - return $params;
353 - }
354 -
355 - /**
356 - * Returns an array with the fields and their descriptions.
357 - *
358 - * field name => field description
359 - *
360 - * @since 1.20
361 - *
362 - * @return array
363 - */
364 - public function getFieldDescriptions() {
365 - return array();
366 - }
367 -
368 - /**
369 - * Get the database type used for read operations.
370 - *
371 - * @since 1.20
372 - *
373 - * @return integer DB_ enum
374 - */
375 - public function getReadDb() {
376 - return $this->readDb;
377 - }
378 -
379 - /**
380 - * Set the database type to use for read operations.
381 - *
382 - * @param integer $db
383 - *
384 - * @since 1.20
385 - */
386 - public function setReadDb( $db ) {
387 - $this->readDb = $db;
388 - }
389 -
390 - /**
391 - * Update the records matching the provided conditions by
392 - * setting the fields that are keys in the $values param to
393 - * their corresponding values.
394 - *
395 - * @since 1.20
396 - *
397 - * @param array $values
398 - * @param array $conditions
399 - *
400 - * @return boolean Success indicator
401 - */
402 - public function update( array $values, array $conditions = array() ) {
403 - $dbw = wfGetDB( DB_MASTER );
404 -
405 - return $dbw->update(
406 - $this->getDBTable(),
407 - $this->getPrefixedValues( $values ),
408 - $this->getPrefixedValues( $conditions ),
409 - __METHOD__
410 - );
411 - }
412 -
413 - /**
414 - * Computes the values of the summary fields of the objects matching the provided conditions.
415 - *
416 - * @since 1.20
417 - *
418 - * @param array|string|null $summaryFields
419 - * @param array $conditions
420 - */
421 - public function updateSummaryFields( $summaryFields = null, array $conditions = array() ) {
422 - $this->setReadDb( DB_MASTER );
423 -
424 - foreach ( $this->select( null, $conditions ) as /* DBDataObject */ $item ) {
425 - $item->loadSummaryFields( $summaryFields );
426 - $item->setSummaryMode( true );
427 - $item->save();
428 - }
429 -
430 - $this->setReadDb( DB_SLAVE );
431 - }
432 -
433 - /**
434 - * Takes in an associative array with field names as keys and
435 - * their values as value. The field names are prefixed with the
436 - * db field prefix.
437 - *
438 - * Field names can also be provided as an array with as first element a table name, such as
439 - * $conditions = array(
440 - * array( array( 'tablename', 'fieldname' ), $value ),
441 - * );
442 - *
443 - * @since 1.20
444 - *
445 - * @param array $values
446 - *
447 - * @return array
448 - */
449 - public function getPrefixedValues( array $values ) {
450 - $prefixedValues = array();
451 -
452 - foreach ( $values as $field => $value ) {
453 - if ( is_integer( $field ) ) {
454 - if ( is_array( $value ) ) {
455 - $field = $value[0];
456 - $value = $value[1];
457 - }
458 - else {
459 - $value = explode( ' ', $value, 2 );
460 - $value[0] = $this->getPrefixedField( $value[0] );
461 - $prefixedValues[] = implode( ' ', $value );
462 - continue;
463 - }
464 - }
465 -
466 - $prefixedValues[$this->getPrefixedField( $field )] = $value;
467 - }
468 -
469 - return $prefixedValues;
470 - }
471 -
472 - /**
473 - * Takes in a field or array of fields and returns an
474 - * array with their prefixed versions, ready for db usage.
475 - *
476 - * @since 1.20
477 - *
478 - * @param array|string $fields
479 - *
480 - * @return array
481 - */
482 - public function getPrefixedFields( array $fields ) {
483 - foreach ( $fields as &$field ) {
484 - $field = $this->getPrefixedField( $field );
485 - }
486 -
487 - return $fields;
488 - }
489 -
490 - /**
491 - * Takes in a field and returns an it's prefixed version, ready for db usage.
492 - *
493 - * @since 1.20
494 - *
495 - * @param string|array $field
496 - *
497 - * @return string
498 - */
499 - public function getPrefixedField( $field ) {
500 - return $this->getFieldPrefix() . $field;
501 - }
502 -
503 - /**
504 - * Takes an array of field names with prefix and returns the unprefixed equivalent.
505 - *
506 - * @since 1.20
507 - *
508 - * @param array $fieldNames
509 - *
510 - * @return array
511 - */
512 - public function unprefixFieldNames( array $fieldNames ) {
513 - return array_map( array( $this, 'unprefixFieldName' ), $fieldNames );
514 - }
515 -
516 - /**
517 - * Takes a field name with prefix and returns the unprefixed equivalent.
518 - *
519 - * @since 1.20
520 - *
521 - * @param string $fieldName
522 - *
523 - * @return string
524 - */
525 - public function unprefixFieldName( $fieldName ) {
526 - return substr( $fieldName, strlen( $this->getFieldPrefix() ) );
527 - }
528 -
529 - public function __construct() {
530 -
531 - }
532 -
533 - /**
534 - * Get an instance of this class.
535 - *
536 - * @since 1.20
537 - *
538 - * @return DBtable
539 - */
540 - public static function singleton() {
541 - static $instance;
542 -
543 - if ( !isset( $instance ) ) {
544 - $class = function_exists( 'get_called_class' ) ? get_called_class() : self::get_called_class();
545 - $instance = new $class;
546 - }
547 -
548 - return $instance;
549 - }
550 -
551 - /**
552 - * Compatibility fallback function so the singleton method works on PHP < 5.3.
553 - * Code borrowed from http://www.php.net/manual/en/function.get-called-class.php#107445
554 - *
555 - * @since 1.20
556 - *
557 - * @return string
558 - */
559 - protected static function get_called_class() {
560 - $bt = debug_backtrace();
561 - $l = count($bt) - 1;
562 - $matches = array();
563 - while(empty($matches) && $l > -1){
564 - $lines = file($bt[$l]['file']);
565 - $callerLine = $lines[$bt[$l]['line']-1];
566 - preg_match('/([a-zA-Z0-9\_]+)::'.$bt[$l--]['function'].'/',
567 - $callerLine,
568 - $matches);
569 - }
570 - if (!isset($matches[1])) $matches[1]=NULL; //for notices
571 - if ($matches[1] == 'self') {
572 - $line = $bt[$l]['line']-1;
573 - while ($line > 0 && strpos($lines[$line], 'class') === false) {
574 - $line--;
575 - }
576 - preg_match('/class[\s]+(.+?)[\s]+/si', $lines[$line], $matches);
577 - }
578 - return $matches[1];
579 - }
580 -
581 - /**
582 - * Get an array with fields from a database result,
583 - * that can be fed directly to the constructor or
584 - * to setFields.
585 - *
586 - * @since 1.20
587 - *
588 - * @param stdClass $result
589 - *
590 - * @return array
591 - */
592 - public function getFieldsFromDBResult( stdClass $result ) {
593 - $result = (array)$result;
594 - return array_combine(
595 - $this->unprefixFieldNames( array_keys( $result ) ),
596 - array_values( $result )
597 - );
598 - }
599 -
600 - /**
601 - * Get a new instance of the class from a database result.
602 - *
603 - * @since 1.20
604 - *
605 - * @param stdClass $result
606 - *
607 - * @return DBDataObject
608 - */
609 - public function newFromDBResult( stdClass $result ) {
610 - return $this->newFromArray( $this->getFieldsFromDBResult( $result ) );
611 - }
612 -
613 - /**
614 - * Get a new instance of the class from an array.
615 - *
616 - * @since 1.20
617 - *
618 - * @param array $data
619 - * @param boolean $loadDefaults
620 - *
621 - * @return DBDataObject
622 - */
623 - public function newFromArray( array $data, $loadDefaults = false ) {
624 - $class = $this->getDataObjectClass();
625 - return new $class( $this, $data, $loadDefaults );
626 - }
627 -
628 - /**
629 - * Return the names of the fields.
630 - *
631 - * @since 1.20
632 - *
633 - * @return array
634 - */
635 - public function getFieldNames() {
636 - return array_keys( $this->getFieldTypes() );
637 - }
638 -
639 - /**
640 - * Gets if the object can take a certain field.
641 - *
642 - * @since 1.20
643 - *
644 - * @param string $name
645 - *
646 - * @return boolean
647 - */
648 - public function canHaveField( $name ) {
649 - return array_key_exists( $name, $this->getFieldTypes() );
650 - }
651 -
652 -}

Follow-up revisions

RevisionCommit summaryAuthorDate
r111594follow up r111591 r111592jeroendedauw22:59, 15 February 2012

Status & tagging log