r111294 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r111293‎ | r111294 | r111295 >
Date:14:05, 12 February 2012
Author:jeroendedauw
Status:deferred
Tags:
Comment:
rem databobject class and rename canHas to canHave
Modified paths:
  • /trunk/extensions/EducationProgram/actions/EPEditAction.php (modified) (history)
  • /trunk/extensions/EducationProgram/includes/DBDataObject.php (deleted) (history)

Diff [purge]

Index: trunk/extensions/EducationProgram/actions/EPEditAction.php
@@ -386,7 +386,7 @@
387387 $value = null;
388388 }
389389
390 - if ( $c::canHasField( $matches[1] ) ) {
 390+ if ( $c::canHaveField( $matches[1] ) ) {
391391 $fields[$matches[1]] = $value;
392392 }
393393 else {
Index: trunk/extensions/EducationProgram/includes/DBDataObject.php
@@ -1,1288 +0,0 @@
2 -<?php
3 -
4 -/**
5 - * Abstract base class for representing objects that are stored in some DB table.
6 - * This is basically an ORM-like wrapper around rows in database tables that
7 - * aims to be both simple and very flexible. It is centered around an associative
8 - * array of fields and various methods to do common interaction with the database.
9 - *
10 - * These methods must be implemented in deriving classes:
11 - * * getFieldTypes
12 - *
13 - * These methods are likely candidates for overriding:
14 - * * getDefaults
15 - * * remove
16 - * * insert
17 - * * saveExisting
18 - * * loadSummaryFields
19 - * * getSummaryFields
20 - *
21 - * Deriving classes must register their table and field prefix in $wgDBDataObjects.
22 - * Syntax: $wgDBDataObjects['DrivingClassName'] = array( 'table' => 'table_name', 'prefix' => 'fieldprefix_' );
23 - * Example: $wgDBDataObjects['EPOrg'] = array( 'table' => 'ep_orgs', 'prefix' => 'org_' );
24 - *
25 - * Main instance methods:
26 - * * getField(s)
27 - * * setField(s)
28 - * * save
29 - * * remove
30 - *
31 - * Main static methods:
32 - * * select
33 - * * update
34 - * * delete
35 - * * count
36 - * * has
37 - * * selectRow
38 - * * selectFields
39 - * * selectFieldsRow
40 - *
41 - * @since 0.1
42 - *
43 - * @file DBDataObject.php
44 - * @ingroup EducationProgram
45 - *
46 - * @licence GNU GPL v3 or later
47 - * @author Jeroen De Dauw < jeroendedauw@gmail.com >
48 - */
49 -abstract class DBDataObject {
50 -
51 - /**
52 - * The fields of the object.
53 - * field name (w/o prefix) => value
54 - *
55 - * @since 0.1
56 - * @var array
57 - */
58 - protected $fields = array( 'id' => null );
59 -
60 - /**
61 - * If the object should update summaries of linked items when changed.
62 - * For example, update the course_count field in universities when a course in courses is deleted.
63 - * Settings this to false can prevent needless updating work in situations
64 - * such as deleting a university, which will then delete all it's courses.
65 - *
66 - * @since 0.1
67 - * @var bool
68 - */
69 - protected $updateSummaries = true;
70 -
71 - /**
72 - * Indicates if the object is in summary mode.
73 - * This mode indicates that only summary fields got updated,
74 - * which allows for optimizations.
75 - *
76 - * @since 0.1
77 - * @var bool
78 - */
79 - protected $inSummaryMode = false;
80 -
81 -
82 - /**
83 - * The database connection to use for read operations.
84 - * Can be changed via @see setReadDb.
85 - *
86 - * @since 0.2
87 - * @var integer DB_ enum
88 - */
89 - protected static $readDb = DB_SLAVE;
90 -
91 - /**
92 - * Returns the name of the database table objects of this type are stored in.
93 - *
94 - * @since 0.1
95 - *
96 - * @throws MWException
97 - * @return string
98 - */
99 - public static function getDBTable() {
100 - global $wgDBDataObjects;
101 - if ( array_key_exists( get_called_class(), $wgDBDataObjects ) ) {
102 - return $wgDBDataObjects[get_called_class()]['table'];
103 - }
104 - else {
105 - throw new MWException( 'Class "' . get_called_class() . '" not found in $wgDBDataObjects' );
106 - }
107 - }
108 -
109 - /**
110 - * Gets the db field prefix.
111 - *
112 - * @since 0.1
113 - *
114 - * @throws MWException
115 - * @return string
116 - */
117 - protected static function getFieldPrefix() {
118 - global $wgDBDataObjects;
119 - if ( array_key_exists( get_called_class(), $wgDBDataObjects ) ) {
120 - return $wgDBDataObjects[get_called_class()]['prefix'];
121 - }
122 - else {
123 - throw new MWException( 'Class "' . get_called_class() . '" not found in $wgDBDataObjects' );
124 - }
125 - }
126 -
127 - /**
128 - * Returns an array with the fields and their types this object contains.
129 - * This corresponds directly to the fields in the database, without prefix.
130 - *
131 - * field name => type
132 - *
133 - * Allowed types:
134 - * * id
135 - * * str
136 - * * int
137 - * * float
138 - * * bool
139 - * * array
140 - *
141 - * @since 0.1
142 - *
143 - * @throws MWException
144 - * @return array
145 - */
146 - protected static function getFieldTypes() {
147 - throw new MWException( 'Class did not implement getFieldTypes' );
148 - }
149 -
150 - /**
151 - * Returns a list of default field values.
152 - * field name => field value
153 - *
154 - * @since 0.1
155 - *
156 - * @return array
157 - */
158 - public static function getDefaults() {
159 - return array();
160 - }
161 -
162 - /**
163 - * Returns a list of the summary fields.
164 - * These are fields that cache computed values, such as the amount of linked objects of $type.
165 - * This is relevant as one might not want to do actions such as log changes when these get updated.
166 - *
167 - * @since 0.1
168 - *
169 - * @return array
170 - */
171 - public static function getSummaryFields() {
172 - return array();
173 - }
174 -
175 - /**
176 - * Constructor.
177 - *
178 - * @since 0.1
179 - *
180 - * @param array|null $fields
181 - * @param boolean $loadDefaults
182 - */
183 - public function __construct( $fields = null, $loadDefaults = false ) {
184 - if ( !is_array( $fields ) ) {
185 - $fields = array();
186 - }
187 -
188 - if ( $loadDefaults ) {
189 - $fields = array_merge( $this->getDefaults(), $fields );
190 - }
191 -
192 - $this->setFields( $fields );
193 - }
194 -
195 - /**
196 - * Load the specified fields from the database.
197 - *
198 - * @since 0.1
199 - *
200 - * @param array|null $fields
201 - * @param boolean $override
202 - * @param boolean $skipLoaded
203 - *
204 - * @return Success indicator
205 - */
206 - public function loadFields( $fields = null, $override = true, $skipLoaded = false ) {
207 - if ( is_null( $this->getId() ) ) {
208 - return false;
209 - }
210 -
211 - if ( is_null( $fields ) ) {
212 - $fields = array_keys( $this->getFieldTypes() );
213 - }
214 -
215 - if ( $skipLoaded ) {
216 - $loadedFields = array_keys( $this->fields );
217 - $fields = array_filter( $fields, function( $field ) use ( $loadedFields ) {
218 - return !in_array( $field, $loadedFields );
219 - } );
220 - }
221 -
222 - if ( count( $fields ) > 0 ) {
223 - $results = $this->rawSelect(
224 - $this->getPrefixedFields( $fields ),
225 - array( $this->getPrefixedField( 'id' ) => $this->getId() ),
226 - array( 'LIMIT' => 1 )
227 - );
228 -
229 - foreach ( $results as $result ) {
230 - $this->setFields( $this->getFieldsFromDBResult( $result ), $override );
231 - return true;
232 - }
233 -
234 - return false;
235 - }
236 -
237 - return true;
238 - }
239 -
240 - /**
241 - * Gets the value of a field.
242 - *
243 - * @since 0.1
244 - *
245 - * @param string $name
246 - * @param mixed $default
247 - *
248 - * @throws MWException
249 - * @return mixed
250 - */
251 - public function getField( $name, $default = null ) {
252 - if ( $this->hasField( $name ) ) {
253 - return $this->fields[$name];
254 - } elseif ( !is_null( $default ) ) {
255 - return $default;
256 - } else {
257 - throw new MWException( 'Attempted to get not-set field ' . $name );
258 - }
259 - }
260 -
261 - /**
262 - * Gets the value of a field but first loads it if not done so already.
263 - *
264 - * @since 0.1
265 - *
266 - * @param string$name
267 - *
268 - * @return mixed
269 - */
270 - public function loadAndGetField( $name ) {
271 - if ( !$this->hasField( $name ) ) {
272 - $this->loadFields( array( $name ) );
273 - }
274 -
275 - return $this->getField( $name );
276 - }
277 -
278 - /**
279 - * Remove a field.
280 - *
281 - * @since 0.1
282 - *
283 - * @param string $name
284 - */
285 - public function removeField( $name ) {
286 - unset( $this->fields[$name] );
287 - }
288 -
289 - /**
290 - * Returns the objects database id.
291 - *
292 - * @since 0.1
293 - *
294 - * @return integer|null
295 - */
296 - public function getId() {
297 - return $this->getField( 'id' );
298 - }
299 -
300 - /**
301 - * Sets the objects database id.
302 - *
303 - * @since 0.1
304 - *
305 - * @param integer|null $id
306 - */
307 - public function setId( $id ) {
308 - return $this->setField( 'id', $id );
309 - }
310 -
311 - /**
312 - * Gets if a certain field is set.
313 - *
314 - * @since 0.1
315 - *
316 - * @param string $name
317 - *
318 - * @return boolean
319 - */
320 - public function hasField( $name ) {
321 - return array_key_exists( $name, $this->fields );
322 - }
323 -
324 - /**
325 - * Gets if the id field is set.
326 - *
327 - * @since 0.1
328 - *
329 - * @return boolean
330 - */
331 - public function hasIdField() {
332 - return $this->hasField( 'id' )
333 - && !is_null( $this->getField( 'id' ) );
334 - }
335 -
336 - /**
337 - * Sets multiple fields.
338 - *
339 - * @since 0.1
340 - *
341 - * @param array $fields The fields to set
342 - * @param boolean $override Override already set fields with the provided values?
343 - */
344 - public function setFields( array $fields, $override = true ) {
345 - foreach ( $fields as $name => $value ) {
346 - if ( $override || !$this->hasField( $name ) ) {
347 - $this->setField( $name, $value );
348 - }
349 - }
350 - }
351 -
352 - /**
353 - * Gets the fields => values to write to the table.
354 - *
355 - * @since 0.1
356 - *
357 - * @return array
358 - */
359 - protected function getWriteValues() {
360 - $values = array();
361 -
362 - foreach ( $this->getFieldTypes() as $name => $type ) {
363 - if ( array_key_exists( $name, $this->fields ) ) {
364 - $value = $this->fields[$name];
365 -
366 - switch ( $type ) {
367 - case 'array':
368 - $value = (array)$value;
369 - case 'blob':
370 - $value = serialize( $value );
371 - }
372 -
373 - $values[$this->getFieldPrefix() . $name] = $value;
374 - }
375 - }
376 -
377 - return $values;
378 - }
379 -
380 - /**
381 - * Serializes the object to an associative array which
382 - * can then easily be converted into JSON or similar.
383 - *
384 - * @since 0.1
385 - *
386 - * @param null|array $fields
387 - * @param boolean $incNullId
388 - *
389 - * @return array
390 - */
391 - public function toArray( $fields = null, $incNullId = false ) {
392 - $data = array();
393 - $setFields = array();
394 -
395 - if ( !is_array( $fields ) ) {
396 - $setFields = $this->getSetFieldNames();
397 - } else {
398 - foreach ( $fields as $field ) {
399 - if ( $this->hasField( $field ) ) {
400 - $setFields[] = $field;
401 - }
402 - }
403 - }
404 -
405 - foreach ( $setFields as $field ) {
406 - if ( $incNullId || $field != 'id' || $this->hasIdField() ) {
407 - $data[$field] = $this->getField( $field );
408 - }
409 - }
410 -
411 - return $data;
412 - }
413 -
414 - /**
415 - * Load the default values, via getDefaults.
416 - *
417 - * @since 0.1
418 - *
419 - * @param boolean $override
420 - */
421 - public function loadDefaults( $override = true ) {
422 - $this->setFields( $this->getDefaults(), $override );
423 - }
424 -
425 - /**
426 - * Writes the answer to the database, either updating it
427 - * when it already exists, or inserting it when it doesn't.
428 - *
429 - * @since 0.1
430 - *
431 - * @return boolean Success indicator
432 - */
433 - public function save() {
434 - if ( $this->hasIdField() ) {
435 - return $this->saveExisting();
436 - } else {
437 - return $this->insert();
438 - }
439 - }
440 -
441 - /**
442 - * Updates the object in the database.
443 - *
444 - * @since 0.1
445 - *
446 - * @return boolean Success indicator
447 - */
448 - protected function saveExisting() {
449 - $dbw = wfGetDB( DB_MASTER );
450 -
451 - $success = $dbw->update(
452 - $this->getDBTable(),
453 - $this->getWriteValues(),
454 - array( $this->getFieldPrefix() . 'id' => $this->getId() ),
455 - __METHOD__
456 - );
457 -
458 - return $success;
459 - }
460 -
461 - /**
462 - * Inserts the object into the database.
463 - *
464 - * @since 0.1
465 - *
466 - * @return boolean Success indicator
467 - */
468 - protected function insert() {
469 - $dbw = wfGetDB( DB_MASTER );
470 -
471 - $result = $dbw->insert(
472 - $this->getDBTable(),
473 - $this->getWriteValues(),
474 - __METHOD__,
475 - array( 'IGNORE' )
476 - );
477 -
478 - if ( $result ) {
479 - $this->setField( 'id', $dbw->insertId() );
480 - }
481 -
482 - return $result;
483 - }
484 -
485 - /**
486 - * Removes the object from the database.
487 - *
488 - * @since 0.1
489 - *
490 - * @return boolean Success indicator
491 - */
492 - public function remove() {
493 - $this->beforeRemove();
494 -
495 - $success = static::delete( array( 'id' => $this->getId() ) );
496 -
497 - if ( $success ) {
498 - $this->onRemoved();
499 - }
500 -
501 - return $success;
502 - }
503 -
504 - /**
505 - * Gets called before an object is removed from the database.
506 - *
507 - * @since 0.1
508 - */
509 - protected function beforeRemove() {
510 - $this->loadFields( $this->getBeforeRemoveFields(), false, true );
511 - }
512 -
513 - /**
514 - * Before removal of an object happens, @see beforeRemove gets called.
515 - * This method loads the fields of which the names have been returned by this one (or all fields if null is returned).
516 - * This allows for loading info needed after removal to get rid of linked data and the like.
517 - *
518 - * @since 0.1
519 - *
520 - * @return array|null
521 - */
522 - protected function getBeforeRemoveFields() {
523 - return array();
524 - }
525 -
526 - /**
527 - * Gets called after successfull removal.
528 - * Can be overriden to get rid of linked data.
529 - *
530 - * @since 0.1
531 - */
532 - protected function onRemoved() {
533 - $this->setField( 'id', null );
534 - }
535 -
536 - /**
537 - * Return the names and values of the fields.
538 - *
539 - * @since 0.1
540 - *
541 - * @return array
542 - */
543 - public function getFields() {
544 - return $this->fields;
545 - }
546 -
547 - /**
548 - * Return the names of the fields.
549 - *
550 - * @since 0.1
551 - *
552 - * @return array
553 - */
554 - public function getSetFieldNames() {
555 - return array_keys( $this->fields );
556 - }
557 -
558 - /**
559 - * Sets the value of a field.
560 - * Strings can be provided for other types,
561 - * so this method can be called from unserialization handlers.
562 - *
563 - * @since 0.1
564 - *
565 - * @param string $name
566 - * @param mixed $value
567 - *
568 - * @throws MWException
569 - */
570 - public function setField( $name, $value ) {
571 - $fields = $this->getFieldTypes();
572 -
573 - if ( array_key_exists( $name, $fields ) ) {
574 - switch ( $fields[$name] ) {
575 - case 'int':
576 - $value = (int)$value;
577 - break;
578 - case 'float':
579 - $value = (float)$value;
580 - break;
581 - case 'bool':
582 - if ( is_string( $value ) ) {
583 - $value = $value !== '0';
584 - } elseif ( is_int( $value ) ) {
585 - $value = $value !== 0;
586 - }
587 - break;
588 - case 'array':
589 - if ( is_string( $value ) ) {
590 - $value = unserialize( $value );
591 - }
592 -
593 - if ( !is_array( $value ) ) {
594 - $value = array();
595 - }
596 - break;
597 - case 'blob':
598 - if ( is_string( $value ) ) {
599 - $value = unserialize( $value );
600 - }
601 - break;
602 - case 'id':
603 - if ( is_string( $value ) ) {
604 - $value = (int)$value;
605 - }
606 - break;
607 - }
608 -
609 - $this->fields[$name] = $value;
610 - } else {
611 - throw new MWException( 'Attempted to set unknown field ' . $name );
612 - }
613 - }
614 -
615 - /**
616 - * Get a new instance of the class from an array.
617 - *
618 - * @since 0.1
619 - *
620 - * @param array $data
621 - * @param boolean $loadDefaults
622 - *
623 - * @return DBDataObject
624 - */
625 - public static function newFromArray( array $data, $loadDefaults = false ) {
626 - return new static( $data, $loadDefaults );
627 - }
628 -
629 - /**
630 - * Get the database type used for read operations.
631 - *
632 - * @since 0.2
633 - * @return integer DB_ enum
634 - */
635 - public static function getReadDb() {
636 - return self::$readDb;
637 - }
638 -
639 - /**
640 - * Set the database type to use for read operations.
641 - *
642 - * @param integer $db
643 - *
644 - * @since 0.2
645 - */
646 - public static function setReadDb( $db ) {
647 - self::$readDb = $db;
648 - }
649 -
650 - /**
651 - * Gets if the object can take a certain field.
652 - *
653 - * @since 0.1
654 - *
655 - * @param string $name
656 - *
657 - * @return boolean
658 - */
659 - public static function canHasField( $name ) {
660 - return array_key_exists( $name, static::getFieldTypes() );
661 - }
662 -
663 - /**
664 - * Takes in a field or array of fields and returns an
665 - * array with their prefixed versions, ready for db usage.
666 - *
667 - * @since 0.1
668 - *
669 - * @param array|string $fields
670 - *
671 - * @return array
672 - */
673 - public static function getPrefixedFields( array $fields ) {
674 - foreach ( $fields as &$field ) {
675 - $field = static::getPrefixedField( $field );
676 - }
677 -
678 - return $fields;
679 - }
680 -
681 - /**
682 - * Takes in a field and returns an it's prefixed version, ready for db usage.
683 - * If the field needs to be prefixed for another table, provide an array in the form
684 - * array( 'tablename', 'fieldname' )
685 - * Where table name is registered in $wgDBDataObjects.
686 - *
687 - * @since 0.1
688 - *
689 - * @param string|array $field
690 - *
691 - * @return string
692 - * @throws MWException
693 - */
694 - public static function getPrefixedField( $field ) {
695 - static $prefixes = false;
696 -
697 - if ( $prefixes === false ) {
698 - foreach ( $GLOBALS['wgDBDataObjects'] as $classInfo ) {
699 - $prefixes[$classInfo['table']] = $classInfo['prefix'];
700 - }
701 - }
702 -
703 - if ( is_array( $field ) && count( $field ) > 1 ) {
704 - if ( array_key_exists( $field[0], $prefixes ) ) {
705 - $prefix = $prefixes[$field[0]];
706 - $field = $field[1];
707 - }
708 - else {
709 - throw new MWException( 'Tried to prefix field with unknown table "' . $field[0] . '"' );
710 - }
711 - }
712 - else {
713 - $prefix = static::getFieldPrefix();
714 - }
715 -
716 - return $prefix . $field;
717 - }
718 -
719 - /**
720 - * Takes in an associative array with field names as keys and
721 - * their values as value. The field names are prefixed with the
722 - * db field prefix.
723 - *
724 - * Field names can also be provided as an array with as first element a table name, such as
725 - * $conditions = array(
726 - * array( array( 'tablename', 'fieldname' ), $value ),
727 - * );
728 - *
729 - * @since 0.1
730 - *
731 - * @param array $values
732 - *
733 - * @return array
734 - */
735 - public static function getPrefixedValues( array $values ) {
736 - $prefixedValues = array();
737 -
738 - foreach ( $values as $field => $value ) {
739 - if ( is_integer( $field ) ) {
740 - if ( is_array( $value ) ) {
741 - $field = $value[0];
742 - $value = $value[1];
743 - }
744 - else {
745 - $value = explode( ' ', $value, 2 );
746 - $value[0] = static::getPrefixedField( $value[0] );
747 - $prefixedValues[] = implode( ' ', $value );
748 - continue;
749 - }
750 - }
751 -
752 - $prefixedValues[static::getPrefixedField( $field )] = $value;
753 - }
754 -
755 - return $prefixedValues;
756 - }
757 -
758 - /**
759 - * Get an array with fields from a database result,
760 - * that can be fed directly to the constructor or
761 - * to setFields.
762 - *
763 - * @since 0.1
764 - *
765 - * @param object $result
766 - *
767 - * @return array
768 - */
769 - public static function getFieldsFromDBResult( $result ) {
770 - $result = (array)$result;
771 - return array_combine(
772 - static::unprefixFieldNames( array_keys( $result ) ),
773 - array_values( $result )
774 - );
775 - }
776 -
777 - /**
778 - * Takes a field name with prefix and returns the unprefixed equivalent.
779 - *
780 - * @since 0.1
781 - *
782 - * @param string $fieldName
783 - *
784 - * @return string
785 - */
786 - public static function unprefixFieldName( $fieldName ) {
787 - return substr( $fieldName, strlen( static::getFieldPrefix() ) );
788 - }
789 -
790 - /**
791 - * Takes an array of field names with prefix and returns the unprefixed equivalent.
792 - *
793 - * @since 0.1
794 - *
795 - * @param array $fieldNames
796 - *
797 - * @return array
798 - */
799 - public static function unprefixFieldNames( array $fieldNames ) {
800 - return array_map( 'static::unprefixFieldName', $fieldNames );
801 - }
802 -
803 - /**
804 - * Get a new instance of the class from a database result.
805 - *
806 - * @since 0.1
807 - *
808 - * @param stdClass $result
809 - *
810 - * @return DBDataObject
811 - */
812 - public static function newFromDBResult( stdClass $result ) {
813 - return static::newFromArray( static::getFieldsFromDBResult( $result ) );
814 - }
815 -
816 - /**
817 - * Removes the object from the database.
818 - *
819 - * @since 0.1
820 - *
821 - * @param array $conditions
822 - *
823 - * @return boolean Success indicator
824 - */
825 - public static function delete( array $conditions ) {
826 - return wfGetDB( DB_MASTER )->delete(
827 - static::getDBTable(),
828 - static::getPrefixedValues( $conditions )
829 - );
830 - }
831 -
832 - /**
833 - * Add an amount (can be negative) to the specified field (needs to be numeric).
834 - *
835 - * @since 0.1
836 - *
837 - * @param string $field
838 - * @param integer $amount
839 - *
840 - * @return boolean Success indicator
841 - */
842 - public static function addToField( $field, $amount ) {
843 - if ( $amount == 0 ) {
844 - return true;
845 - }
846 -
847 - if ( !static::hasIdField() ) {
848 - return false;
849 - }
850 -
851 - $absoluteAmount = abs( $amount );
852 - $isNegative = $amount < 0;
853 -
854 - $dbw = wfGetDB( DB_MASTER );
855 -
856 - $fullField = static::getPrefixedField( $field );
857 -
858 - $success = $dbw->update(
859 - static::getDBTable(),
860 - array( "$fullField=$fullField" . ( $isNegative ? '-' : '+' ) . $absoluteAmount ),
861 - array( static::getPrefixedField( 'id' ) => static::getId() ),
862 - __METHOD__
863 - );
864 -
865 - if ( $success && static::hasField( $field ) ) {
866 - static::setField( $field, static::getField( $field ) + $amount );
867 - }
868 -
869 - return $success;
870 - }
871 -
872 - /**
873 - * Selects the the specified fields of the records matching the provided
874 - * conditions and returns them as DBDataObject. Field names get prefixed.
875 - *
876 - * @since 0.1
877 - *
878 - * @param array|string|null $fields
879 - * @param array $conditions
880 - * @param array $options
881 - * @param array $joinConds
882 - *
883 - * @return array of self
884 - */
885 - public static function select( $fields = null, array $conditions = array(), array $options = array(), array $joinConds = array() ) {
886 - $result = static::selectFields( $fields, $conditions, $options, $joinConds, false );
887 -
888 - $objects = array();
889 -
890 - foreach ( $result as $record ) {
891 - $objects[] = static::newFromArray( $record );
892 - }
893 -
894 - return $objects;
895 - }
896 -
897 - /**
898 - * Selects the the specified fields of the records matching the provided
899 - * conditions and returns them as associative arrays.
900 - * Provided field names get prefixed.
901 - * Returned field names will not have a prefix.
902 - *
903 - * When $collapse is true:
904 - * If one field is selected, each item in the result array will be this field.
905 - * If two fields are selected, each item in the result array will have as key
906 - * the first field and as value the second field.
907 - * If more then two fields are selected, each item will be an associative array.
908 - *
909 - * @since 0.1
910 - *
911 - * @param array|string|null $fields
912 - * @param array $conditions
913 - * @param array $options
914 - * @param array $joinConds
915 - * @param boolean $collapse Set to false to always return each result row as associative array.
916 - *
917 - * @return array of array
918 - */
919 - public static function selectFields( $fields = null, array $conditions = array(), array $options = array(), array $joinConds = array(), $collapse = true ) {
920 - if ( is_null( $fields ) ) {
921 - $fields = array_keys( static::getFieldTypes() );
922 - }
923 - else {
924 - $fields = (array)$fields;
925 - }
926 -
927 - $tables = array( static::getDBTable() );
928 - $joinConds = static::getProcessedJoinConds( $joinConds, $tables );
929 -
930 - $result = static::rawSelect(
931 - static::getPrefixedFields( $fields ),
932 - static::getPrefixedValues( $conditions ),
933 - $options,
934 - $joinConds,
935 - $tables
936 - );
937 -
938 - $objects = array();
939 -
940 - foreach ( $result as $record ) {
941 - $objects[] = static::getFieldsFromDBResult( $record );
942 - }
943 -
944 - if ( $collapse ) {
945 - if ( count( $fields ) === 1 ) {
946 - $objects = array_map( function( $object ) { return array_shift( $object ); } , $objects );
947 - }
948 - elseif ( count( $fields ) === 2 ) {
949 - $o = array();
950 -
951 - foreach ( $objects as $object ) {
952 - $o[array_shift( $object )] = array_shift( $object );
953 - }
954 -
955 - $objects = $o;
956 - }
957 - }
958 -
959 - return $objects;
960 - }
961 -
962 - /**
963 - * Process the join conditions. This includes prefixing table and field names,
964 - * and adding of needed tables.
965 - *
966 - * @since 0.1
967 - *
968 - * @param array $joinConds Join conditions without prefixes and fields in array rather then string with equals sign.
969 - * @param array $tables List of tables to which the extra needed ones get added.
970 - *
971 - * @return array Join conditions ready to be fed to MediaWikis native select function.
972 - */
973 - protected static function getProcessedJoinConds( array $joinConds, array &$tables ) {
974 - $conds = array();
975 -
976 - foreach ( $joinConds as $table => $joinCond ) {
977 - if ( !in_array( $table, $tables ) ) {
978 - $tables[] = $table;
979 - }
980 -
981 - $cond = array( $joinCond[0], array() );
982 -
983 - foreach ( $joinCond[1] as $joinCondPart ) {
984 - $parts = array(
985 - static::getPrefixedField( $joinCondPart[0] ),
986 - static::getPrefixedField( $joinCondPart[1] ),
987 - );
988 -
989 - if ( !in_array( $joinCondPart[0][0], $tables ) ) {
990 - $tables[] = $joinCondPart[0][0];
991 - }
992 -
993 - if ( !in_array( $joinCondPart[1][0], $tables ) ) {
994 - $tables[] = $joinCondPart[1][0];
995 - }
996 -
997 - $cond[1][] = implode( '=', $parts );
998 - }
999 -
1000 - $conds[$table] = $cond;
1001 - }
1002 -
1003 - return $conds;
1004 - }
1005 -
1006 - /**
1007 - * Selects the the specified fields of the first matching record.
1008 - * Field names get prefixed.
1009 - *
1010 - * @since 0.1
1011 - *
1012 - * @param array|string|null $fields
1013 - * @param array $conditions
1014 - * @param array $options
1015 - * @param array $joinConds
1016 - *
1017 - * @return EPBObject|false
1018 - */
1019 - public static function selectRow( $fields = null, array $conditions = array(), array $options = array(), array $joinConds = array() ) {
1020 - $options['LIMIT'] = 1;
1021 -
1022 - $objects = static::select( $fields, $conditions, $options, $joinConds );
1023 -
1024 - return count( $objects ) > 0 ? $objects[0] : false;
1025 - }
1026 -
1027 - /**
1028 - * Selects the the specified fields of the first record matching the provided
1029 - * conditions and returns it as an associative array, or false when nothing matches.
1030 - * This method makes use of selectFields and expects the same parameters and
1031 - * returns the same results (if there are any, if there are none, this method returns false).
1032 - * @see DBDataObject::selectFields
1033 - *
1034 - * @since 0.1
1035 - *
1036 - * @param array|string|null $fields
1037 - * @param array $conditions
1038 - * @param array $options
1039 - * @param array $joinConds
1040 - * @param boolean $collapse Set to false to always return each result row as associative array.
1041 - *
1042 - * @return mixed|array|false
1043 - */
1044 - public static function selectFieldsRow( $fields = null, array $conditions = array(), array $options = array(), array $joinConds = array(), $collapse = true ) {
1045 - $options['LIMIT'] = 1;
1046 -
1047 - $objects = static::selectFields( $fields, $conditions, $options, $joinConds, $collapse );
1048 -
1049 - return count( $objects ) > 0 ? $objects[0] : false;
1050 - }
1051 -
1052 - /**
1053 - * Returns if there is at least one record matching the provided conditions.
1054 - * Condition field names get prefixed.
1055 - *
1056 - * @since 0.1
1057 - *
1058 - * @param array $conditions
1059 - *
1060 - * @return boolean
1061 - */
1062 - public static function has( array $conditions = array() ) {
1063 - return static::selectRow( array( 'id' ), $conditions ) !== false;
1064 - }
1065 -
1066 - /**
1067 - * Returns the amount of matching records.
1068 - * Condition field names get prefixed.
1069 - *
1070 - * @since 0.1
1071 - *
1072 - * @param array $conditions
1073 - * @param array $options
1074 - *
1075 - * @return integer
1076 - */
1077 - public static function count( array $conditions = array(), array $options = array() ) {
1078 - $res = static::rawSelect(
1079 - array( 'COUNT(*) AS rowcount' ),
1080 - static::getPrefixedValues( $conditions ),
1081 - $options
1082 - )->fetchObject();
1083 -
1084 - return $res->rowcount;
1085 - }
1086 -
1087 - /**
1088 - * Selects the the specified fields of the records matching the provided
1089 - * conditions. Field names do NOT get prefixed.
1090 - *
1091 - * @since 0.1
1092 - *
1093 - * @param array $fields
1094 - * @param array $conditions
1095 - * @param array $options
1096 - * @param array $joinConds
1097 - * @param array $tables
1098 - *
1099 - * @return ResultWrapper
1100 - */
1101 - public static function rawSelect( array $fields, array $conditions = array(), array $options = array(), array $joinConds = array(), array $tables = null ) {
1102 - if ( is_null( $tables ) ) {
1103 - $tables = static::getDBTable();
1104 - }
1105 -
1106 - $dbr = wfGetDB( static::getReadDb() );
1107 -
1108 - return $dbr->select(
1109 - $tables,
1110 - $fields,
1111 - count( $conditions ) == 0 ? '' : $conditions,
1112 - __METHOD__,
1113 - $options,
1114 - $joinConds
1115 - );
1116 - }
1117 -
1118 - /**
1119 - * Update the records matching the provided conditions by
1120 - * setting the fields that are keys in the $values param to
1121 - * their corresponding values.
1122 - *
1123 - * @since 0.1
1124 - *
1125 - * @param array $values
1126 - * @param array $conditions
1127 - *
1128 - * @return boolean Success indicator
1129 - */
1130 - public static function update( array $values, array $conditions = array() ) {
1131 - $dbw = wfGetDB( DB_MASTER );
1132 -
1133 - return $dbw->update(
1134 - static::getDBTable(),
1135 - static::getPrefixedValues( $values ),
1136 - static::getPrefixedValues( $conditions ),
1137 - __METHOD__
1138 - );
1139 - }
1140 -
1141 - /**
1142 - * Return the names of the fields.
1143 - *
1144 - * @since 0.1
1145 - *
1146 - * @return array
1147 - */
1148 - public static function getFieldNames() {
1149 - return array_keys( static::getFieldTypes() );
1150 - }
1151 -
1152 - /**
1153 - * Returns an array with the fields and their descriptions.
1154 - *
1155 - * field name => field description
1156 - *
1157 - * @since 0.1
1158 - *
1159 - * @return array
1160 - */
1161 - public static function getFieldDescriptions() {
1162 - return array();
1163 - }
1164 -
1165 - /**
1166 - * Get API parameters for the fields supported by this object.
1167 - *
1168 - * @since 0.1
1169 - *
1170 - * @param boolean $requireParams
1171 - * @param boolean $setDefaults
1172 - *
1173 - * @return array
1174 - */
1175 - public static function getAPIParams( $requireParams = false, $setDefaults = false ) {
1176 - $typeMap = array(
1177 - 'id' => 'integer',
1178 - 'int' => 'integer',
1179 - 'float' => 'NULL',
1180 - 'str' => 'string',
1181 - 'bool' => 'integer',
1182 - 'array' => 'string',
1183 - 'blob' => 'string',
1184 - );
1185 -
1186 - $params = array();
1187 - $defaults = static::getDefaults();
1188 -
1189 - foreach ( static::getFieldTypes() as $field => $type ) {
1190 - if ( $field == 'id' ) {
1191 - continue;
1192 - }
1193 -
1194 - $hasDefault = array_key_exists( $field, $defaults );
1195 -
1196 - $params[$field] = array(
1197 - ApiBase::PARAM_TYPE => $typeMap[$type],
1198 - ApiBase::PARAM_REQUIRED => $requireParams && !$hasDefault
1199 - );
1200 -
1201 - if ( $type == 'array' ) {
1202 - $params[$field][ApiBase::PARAM_ISMULTI] = true;
1203 - }
1204 -
1205 - if ( $setDefaults && $hasDefault ) {
1206 - $default = is_array( $defaults[$field] ) ? implode( '|', $defaults[$field] ) : $defaults[$field];
1207 - $params[$field][ApiBase::PARAM_DFLT] = $default;
1208 - }
1209 - }
1210 -
1211 - return $params;
1212 - }
1213 -
1214 - /**
1215 - * Computes and updates the values of the summary fields.
1216 - *
1217 - * @since 0.1
1218 - *
1219 - * @param array|string|null $summaryFields
1220 - */
1221 - public function loadSummaryFields( $summaryFields = null ) {
1222 -
1223 - }
1224 -
1225 - /**
1226 - * Computes the values of the summary fields of the objects matching the provided conditions.
1227 - *
1228 - * @since 0.1
1229 - *
1230 - * @param array|string|null $summaryFields
1231 - * @param array $conditions
1232 - */
1233 - public static function updateSummaryFields( $summaryFields = null, array $conditions = array() ) {
1234 - self::setReadDb( DB_MASTER );
1235 -
1236 - foreach ( self::select( null, $conditions ) as /* DBDataObject */ $item ) {
1237 - $item->loadSummaryFields( $summaryFields );
1238 - $item->setSummaryMode( true );
1239 - $item->saveExisting();
1240 - }
1241 -
1242 - self::setReadDb( DB_SLAVE );
1243 - }
1244 -
1245 - /**
1246 - * Sets the value for the @see $updateSummaries field.
1247 - *
1248 - * @since 0.1
1249 - *
1250 - * @param boolean $update
1251 - */
1252 - public function setUpdateSummaries( $update ) {
1253 - $this->updateSummaries = $update;
1254 - }
1255 -
1256 - /**
1257 - * Sets the value for the @see $inSummaryMode field.
1258 - *
1259 - * @since 0.1
1260 - *
1261 - * @param boolean $update
1262 - */
1263 - public function setSummaryMode( $summaryMode ) {
1264 - $this->inSummaryMode = $summaryMode;
1265 - }
1266 -
1267 - /**
1268 - * Return if any fields got changed.
1269 - *
1270 - * @since 0.1
1271 - *
1272 - * @param DBDataObject $object
1273 - * @param boolean $excludeSummaryFields When set to true, summary field changes are ignored.
1274 - *
1275 - * @return boolean
1276 - */
1277 - protected function fieldsChanged( DBDataObject $object, $excludeSummaryFields = false ) {
1278 - foreach ( $this->fields as $name => $value ) {
1279 - $excluded = $excludeSummaryFields && in_array( $name, $this->getSummaryFields() );
1280 -
1281 - if ( !$excluded && $object->getField( $name ) !== $value ) {
1282 - return true;
1283 - }
1284 - }
1285 -
1286 - return false;
1287 - }
1288 -
1289 -}

Status & tagging log