Index: trunk/extensions/EducationProgram/specials/SpecialEditInstitution.php |
— | — | @@ -48,8 +48,6 @@ |
49 | 49 | }, |
50 | 50 | ); |
51 | 51 | |
52 | | - $countries = efEpGetCountries(); |
53 | | - |
54 | 52 | $fields['country'] = array ( |
55 | 53 | 'type' => 'select', |
56 | 54 | 'label-message' => 'educationprogram-org-edit-country', |
Index: trunk/extensions/EducationProgram/specials/SpecialEditCourse.php |
— | — | @@ -1 +1,69 @@ |
2 | 2 | <?php |
| 3 | + |
| 4 | +/** |
| 5 | + * Adittion and modification interface for courses. |
| 6 | + * |
| 7 | + * @since 0.1 |
| 8 | + * |
| 9 | + * @file SpecialEditCourse.php |
| 10 | + * @ingroup EducationProgram |
| 11 | + * |
| 12 | + * @licence GNU GPL v3 or later |
| 13 | + * @author Jeroen De Dauw < jeroendedauw@gmail.com > |
| 14 | + */ |
| 15 | +class SpecialEditCourse extends SpecialEPFormPage { |
| 16 | + |
| 17 | + /** |
| 18 | + * Constructor. |
| 19 | + * |
| 20 | + * @since 0.1 |
| 21 | + */ |
| 22 | + public function __construct() { |
| 23 | + parent::__construct( 'EditCourse', 'epmentor', 'EPCourse', 'Courses' ); |
| 24 | + } |
| 25 | + |
| 26 | + /** |
| 27 | + * (non-PHPdoc) |
| 28 | + * @see SpecialEPFormPage::getFormFields() |
| 29 | + * @return array |
| 30 | + */ |
| 31 | + protected function getFormFields() { |
| 32 | + $fields = parent::getFormFields(); |
| 33 | + |
| 34 | + $fields['name'] = array ( |
| 35 | + 'type' => 'text', |
| 36 | + 'label-message' => 'ep-course-edit-name', |
| 37 | + 'required' => true, |
| 38 | + 'validation-callback' => function ( $value, array $alldata = null ) { |
| 39 | + return strlen( $value ) < 5 ? wfMsg( 'ep-course-invalid-name' ) : true; |
| 40 | + }, |
| 41 | + ); |
| 42 | + |
| 43 | + $orgOptions = EPOrg::getOrgOptions( EPOrg::getEditableOrgs( $this->getUser() ) ); |
| 44 | + |
| 45 | + $fields['org'] = array ( |
| 46 | + 'type' => 'select', |
| 47 | + 'label-message' => 'ep-course-edit-org', |
| 48 | + 'required' => true, |
| 49 | + 'options' => $orgOptions, |
| 50 | + 'validation-callback' => function ( $value, array $alldata = null ) { |
| 51 | + return strlen( $value ) < 10 ? wfMsg( 'ep-course-invalid-description' ) : true; |
| 52 | + }, |
| 53 | + 'default' => array_shift( $orgOptions ) |
| 54 | + ); |
| 55 | + |
| 56 | + $fields['description'] = array ( |
| 57 | + 'type' => 'textarea', |
| 58 | + 'label-message' => 'ep-course-edit-description', |
| 59 | + 'required' => true, |
| 60 | + 'validation-callback' => function ( $value, array $alldata = null ) { |
| 61 | + return strlen( $value ) < 10 ? wfMsg( 'ep-course-invalid-description' ) : true; |
| 62 | + }, |
| 63 | + 'default' => '', |
| 64 | + 'rows' => 5 |
| 65 | + ); |
| 66 | + |
| 67 | + return $this->processFormFields( $fields ); |
| 68 | + } |
| 69 | + |
| 70 | +} |
Index: trunk/extensions/EducationProgram/includes/EPMentor.php |
— | — | @@ -59,7 +59,12 @@ |
60 | 60 | * @return array of EPOrg |
61 | 61 | */ |
62 | 62 | public function getOrgs( array $fields = null ) { |
63 | | - return array(); // TODO |
| 63 | + return EPOrg::select( |
| 64 | + $fields, |
| 65 | + array( array( 'ep_mentors_per_org', 'mentor_id' ), $this->getId() ), |
| 66 | + array(), |
| 67 | + array( 'orgs' => array( 'INNER JOIN', array( array( array( 'ep_mentors_per_org', 'org_id' ), array( 'orgs', 'id' ) ) ) ) ) |
| 68 | + ); |
64 | 69 | } |
65 | 70 | |
66 | 71 | /** |
Index: trunk/extensions/EducationProgram/includes/EPOrg.php |
— | — | @@ -59,5 +59,46 @@ |
60 | 60 | 'country' => '', |
61 | 61 | ); |
62 | 62 | } |
| 63 | + |
| 64 | + public static function getOrgOptions( array /* EPOrg */ $orgs ) { |
| 65 | + $options = array(); |
| 66 | + |
| 67 | + foreach ( $orgs as /* EPOrg */ $org ) { |
| 68 | + $options[$org->getField( 'name' )] = $org->getId(); |
| 69 | + } |
| 70 | + |
| 71 | + return $options; |
| 72 | + } |
| 73 | + |
| 74 | + /** |
| 75 | + * Returns the list of orgs that the specified user can edit. |
| 76 | + * |
| 77 | + * @since 0.1 |
| 78 | + * |
| 79 | + * @param User|int $user |
| 80 | + * @param array|null $fields |
| 81 | + * |
| 82 | + * @return array of EPOrg |
| 83 | + */ |
| 84 | + public static function getEditableOrgs( $user, array $fields = null ) { |
| 85 | + if ( is_int( $user ) ) { |
| 86 | + $userId = $user; |
| 87 | + $user = User::newFromId( $user ); |
| 88 | + } |
| 89 | + else { |
| 90 | + $userId = $user->getId(); |
| 91 | + } |
| 92 | + |
| 93 | + if ( $user->isAllowed( 'epadmin' ) ) { |
| 94 | + return self::select( $fields ); |
| 95 | + } |
| 96 | + elseif ( $user->isAllowed( 'epmentor' ) ) { |
| 97 | + $mentor = EPMentor::selectRow( 'id', array( 'user_id' => $userId ) ); |
| 98 | + return $mentor === false ? array() : $mentor->getOrgs( $fields ); |
| 99 | + } |
| 100 | + else { |
| 101 | + return array(); |
| 102 | + } |
| 103 | + } |
63 | 104 | |
64 | 105 | } |
Index: trunk/extensions/EducationProgram/includes/EPDBObject.php |
— | — | @@ -47,7 +47,13 @@ |
48 | 48 | * @return string |
49 | 49 | */ |
50 | 50 | public static function getDBTable() { |
51 | | - throw new MWException( 'Class did not implement getDBTable' ); |
| 51 | + global $egEPDBObjects; |
| 52 | + if ( array_key_exists( __CLASS__, $egEPDBObjects ) ) { |
| 53 | + return $egEPDBObjects[__CLASS__]['table']; |
| 54 | + } |
| 55 | + else { |
| 56 | + throw new MWException( 'Class "' . __CLASS__ . '" not found in $egEPDBObjects' ); |
| 57 | + } |
52 | 58 | } |
53 | 59 | |
54 | 60 | /** |
— | — | @@ -59,7 +65,13 @@ |
60 | 66 | * @return string |
61 | 67 | */ |
62 | 68 | protected static function getFieldPrefix() { |
63 | | - throw new MWException( 'Class did not implement getFieldPrefix' ); |
| 69 | + global $egEPDBObjects; |
| 70 | + if ( array_key_exists( __CLASS__, $egEPDBObjects ) ) { |
| 71 | + return $egEPDBObjects[__CLASS__]['prefix']; |
| 72 | + } |
| 73 | + else { |
| 74 | + throw new MWException( 'Class "' . __CLASS__ . '" not found in $egEPDBObjects' ); |
| 75 | + } |
64 | 76 | } |
65 | 77 | |
66 | 78 | /** |
— | — | @@ -515,11 +527,9 @@ |
516 | 528 | * |
517 | 529 | * @return array |
518 | 530 | */ |
519 | | - public static function getPrefixedFields( $fields ) { |
520 | | - $fields = (array)$fields; |
521 | | - |
| 531 | + public static function getPrefixedFields( array $fields ) { |
522 | 532 | foreach ( $fields as &$field ) { |
523 | | - $field = static::getFieldPrefix() . $field; |
| 533 | + $field = static::getPrefixedField( $field ); |
524 | 534 | } |
525 | 535 | |
526 | 536 | return $fields; |
— | — | @@ -527,21 +537,51 @@ |
528 | 538 | |
529 | 539 | /** |
530 | 540 | * Takes in a field and returns an it's prefixed version, ready for db usage. |
| 541 | + * If the field needs to be prefixed for another table, provide an array in the form |
| 542 | + * array( 'tablename', 'fieldname' ) |
| 543 | + * Where table name is registered in $egEPDBObjects. |
531 | 544 | * |
532 | 545 | * @since 0.1 |
533 | 546 | * |
534 | | - * @param string $field |
| 547 | + * @param string|array $field |
535 | 548 | * |
536 | 549 | * @return string |
| 550 | + * @throws MWException |
537 | 551 | */ |
538 | 552 | public static function getPrefixedField( $field ) { |
539 | | - return static::getFieldPrefix() . $field; |
| 553 | + static $prefixes = false; |
| 554 | + |
| 555 | + if ( $prefixes === false ) { |
| 556 | + foreach ( $GLOBALS['egEPDBObjects'] as $classOrIndex => $object ) { |
| 557 | + $prefixes[$object['table']] = $object['prefix']; |
| 558 | + } |
| 559 | + } |
| 560 | + |
| 561 | + if ( is_array( $field ) && count( $field ) > 1 ) { |
| 562 | + if ( array_key_exists( $field[0], $prefixes ) ) { |
| 563 | + $prefix = $prefixes[$field[0]]; |
| 564 | + $field = $field[1]; |
| 565 | + } |
| 566 | + else { |
| 567 | + throw new MWException( 'Tried to prefix field with unknown table "' . $field[0] . '"' ); |
| 568 | + } |
| 569 | + } |
| 570 | + else { |
| 571 | + $prefix = static::getFieldPrefix(); |
| 572 | + } |
| 573 | + |
| 574 | + return $prefix . $field; |
540 | 575 | } |
541 | 576 | |
542 | 577 | /** |
543 | 578 | * Takes in an associative array with field names as keys and |
544 | 579 | * their values as value. The field names are prefixed with the |
545 | 580 | * db field prefix. |
| 581 | + * |
| 582 | + * Field names can also be provdied as an array with as first element a table name, such as |
| 583 | + * $conditions = array( |
| 584 | + * array( array( 'tablename', 'fieldname' ), $value ), |
| 585 | + * ); |
546 | 586 | * |
547 | 587 | * @since 0.1 |
548 | 588 | * |
— | — | @@ -553,7 +593,12 @@ |
554 | 594 | $prefixedValues = array(); |
555 | 595 | |
556 | 596 | foreach ( $values as $field => $value ) { |
557 | | - $prefixedValues[static::getFieldPrefix() . $field] = $value; |
| 597 | + if ( is_integer( $field ) ) { |
| 598 | + $field = $value[0]; |
| 599 | + $value = $value[1]; |
| 600 | + } |
| 601 | + |
| 602 | + $prefixedValues[static::getPrefixedField( $field )] = $value; |
558 | 603 | } |
559 | 604 | |
560 | 605 | return $prefixedValues; |
— | — | @@ -682,18 +727,24 @@ |
683 | 728 | * @param array|string|null $fields |
684 | 729 | * @param array $conditions |
685 | 730 | * @param array $options |
| 731 | + * @param array $joinConds |
686 | 732 | * |
687 | 733 | * @return array of self |
688 | 734 | */ |
689 | | - public static function select( $fields = null, array $conditions = array(), array $options = array() ) { |
| 735 | + public static function select( $fields = null, array $conditions = array(), array $options = array(), array $joinConds = array() ) { |
690 | 736 | if ( is_null( $fields ) ) { |
691 | 737 | $fields = array_keys( static::getFieldTypes() ); |
692 | 738 | } |
693 | 739 | |
| 740 | + $tables = array( static::getDBTable() ); |
| 741 | + $joinConds = static::getProcessedJoinConds( $joinConds, $tables ); |
| 742 | + |
694 | 743 | $result = static::rawSelect( |
695 | 744 | static::getPrefixedFields( $fields ), |
696 | 745 | static::getPrefixedValues( $conditions ), |
697 | | - $options |
| 746 | + $options, |
| 747 | + $joinConds, |
| 748 | + $tables |
698 | 749 | ); |
699 | 750 | |
700 | 751 | $objects = array(); |
— | — | @@ -704,6 +755,42 @@ |
705 | 756 | |
706 | 757 | return $objects; |
707 | 758 | } |
| 759 | + |
| 760 | + /** |
| 761 | + * Process the join conditions. This includes prefixing table and field names, |
| 762 | + * and adding of needed tables. |
| 763 | + * |
| 764 | + * @since 0.1 |
| 765 | + * |
| 766 | + * @param array $joinConds Join conditions without prefixes and fields in array rather then string with equals sign. |
| 767 | + * @param array $tables List of tables to which the extra needed ones get added. |
| 768 | + * |
| 769 | + * @return array Join conditions ready to be fed to MediaWikis native select function. |
| 770 | + */ |
| 771 | + protected static function getProcessedJoinConds( array $joinConds, array &$tables ) { |
| 772 | + $conds = array(); |
| 773 | + |
| 774 | + foreach ( $joinConds as $table => $joinCond ) { |
| 775 | + if ( !in_array( $table, $tables ) ) { |
| 776 | + $tables[] = $table; |
| 777 | + } |
| 778 | + |
| 779 | + $cond = array( $joinCond[0], array() ); |
| 780 | + |
| 781 | + foreach ( $joinCond[1] as $joinCondPart ) { |
| 782 | + $parts = array( |
| 783 | + static::getPrefixedField( $joinCondPart[0] ), |
| 784 | + static::getPrefixedField( $joinCondPart[1] ), |
| 785 | + ); |
| 786 | + |
| 787 | + $cond[1][] = implode( '=', $parts ); |
| 788 | + } |
| 789 | + |
| 790 | + $conds = $cond; |
| 791 | + } |
| 792 | + |
| 793 | + return $conds; |
| 794 | + } |
708 | 795 | |
709 | 796 | /** |
710 | 797 | * Selects the the specified fields of the first matching record. |
— | — | @@ -769,18 +856,24 @@ |
770 | 857 | * @param array|null $fields |
771 | 858 | * @param array $conditions |
772 | 859 | * @param array $options |
| 860 | + * @param array $joinConds |
773 | 861 | * |
774 | 862 | * @return ResultWrapper |
775 | 863 | */ |
776 | | - public static function rawSelect( $fields = null, array $conditions = array(), array $options = array() ) { |
| 864 | + public static function rawSelect( $fields = null, array $conditions = array(), array $options = array(), array $joinConds = array(), array $tables = null ) { |
| 865 | + if ( is_null( $tables ) ) { |
| 866 | + $tables = static::getDBTable(); |
| 867 | + } |
| 868 | + |
777 | 869 | $dbr = wfGetDB( static::getReadDb() ); |
778 | 870 | |
779 | 871 | return $dbr->select( |
780 | | - static::getDBTable(), |
| 872 | + $tables, |
781 | 873 | $fields, |
782 | 874 | count( $conditions ) == 0 ? '' : $conditions, |
783 | 875 | __METHOD__, |
784 | | - $options |
| 876 | + $options, |
| 877 | + $joinConds |
785 | 878 | ); |
786 | 879 | } |
787 | 880 | |
Index: trunk/extensions/EducationProgram/EducationProgram.php |
— | — | @@ -106,6 +106,16 @@ |
107 | 107 | $wgSpecialPageGroups['EditInstitution'] = 'education'; |
108 | 108 | $wgSpecialPageGroups['EditTerm'] = 'education'; |
109 | 109 | |
| 110 | +// DB object classes |
| 111 | +$egEPDBObjects = array(); |
| 112 | +$egEPDBObjects['EPOrg'] = array( 'table' => 'ep_orgs', 'prefix' => 'org_' ); |
| 113 | +$egEPDBObjects['EPCourse'] = array( 'table' => 'ep_courses', 'prefix' => 'course_' ); |
| 114 | +$egEPDBObjects['EPTerm'] = array( 'table' => 'ep_terms', 'prefix' => 'term_' ); |
| 115 | +$egEPDBObjects['EPMentor'] = array( 'table' => 'ep_mentors', 'prefix' => 'mentor_' ); |
| 116 | +$egEPDBObjects['EPStudent'] = array( 'table' => 'ep_students', 'prefix' => 'student_' ); |
| 117 | +$egEPDBObjects[] = array( 'table' => 'ep_students_per_term', 'prefix' => 'spt_' ); |
| 118 | +$egEPDBObjects[] = array( 'table' => 'ep_mentors_per_org', 'prefix' => 'mpo_' ); |
| 119 | + |
110 | 120 | // API |
111 | 121 | |
112 | 122 | |