r103811 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r103810‎ | r103811 | r103812 >
Date:14:41, 21 November 2011
Author:danwe
Status:deferred
Tags:
Comment:
'#arraymerge', '#arrayunion', '#arraydiff' and '#arrayintersect' can handle more than two arrays now
Modified paths:
  • /trunk/extensions/ArrayExtension/ArrayExtension.php (modified) (history)
  • /trunk/extensions/ArrayExtension/RELEASE-NOTES (modified) (history)

Diff [purge]

Index: trunk/extensions/ArrayExtension/ArrayExtension.php
@@ -64,7 +64,8 @@
6565
6666
6767 /**
68 - * Full compatbility to versions before 1.4
 68+ * Full compatbility to versions before 1.4.
 69+ * Set to true by default since version 2.0.
6970 *
7071 * @since 1.4 alpha
7172 *
@@ -120,10 +121,10 @@
121122 self::initFunction( $parser, 'arrayreset', SFH_OBJECT_ARGS );
122123 self::initFunction( $parser, 'arrayunique' );
123124 self::initFunction( $parser, 'arraysort' );
124 - self::initFunction( $parser, 'arraymerge' );
125 - self::initFunction( $parser, 'arrayunion' );
126 - self::initFunction( $parser, 'arraydiff' );
127 - self::initFunction( $parser, 'arrayintersect' );
 125+ self::initFunction( $parser, 'arraymerge', SFH_OBJECT_ARGS );
 126+ self::initFunction( $parser, 'arrayunion', SFH_OBJECT_ARGS );
 127+ self::initFunction( $parser, 'arraydiff', SFH_OBJECT_ARGS );
 128+ self::initFunction( $parser, 'arrayintersect', SFH_OBJECT_ARGS );
128129
129130 return true;
130131 }
@@ -157,7 +158,7 @@
158159 ####################
159160
160161 ///////////////////////////////////////////////////////////
161 - // PART 1. constructor
 162+ // PART 1. Array Construction
162163 ///////////////////////////////////////////////////////////
163164
164165 /**
@@ -271,7 +272,7 @@
272273
273274
274275 ///////////////////////////////////////////////////////////
275 - // PART 2. print
 276+ // PART 2. Extracting Information
276277 ///////////////////////////////////////////////////////////
277278
278279
@@ -543,11 +544,50 @@
544545 $store->setArray( $arrayId_new, $newArr );
545546 return '';
546547 }
 548+
 549+ /**
 550+ * extract a slice from an array
 551+ * usage:
 552+ * {{#arrayslice:arrayid_new|arrayid|offset|length}}
 553+ *
 554+ * extract a slice from an array
 555+ * see: http://www.php.net/manual/en/function.array-slice.php
 556+ */
 557+ static function pf_arrayslice( Parser &$parser, $arrayId_new, $arrayId = null , $offset = 0, $length = null ) {
 558+ $store = self::get( $parser );
 559+ if( $arrayId === null ) {
 560+ global $egArrayExtensionCompatbilityMode;
 561+ if( ! $egArrayExtensionCompatbilityMode ) { // COMPATBILITY-MODE
 562+ $store->setArray( $arrayId_new );
 563+ }
 564+ return '';
 565+ }
 566+ // get target array before overwriting it in any way
 567+ $array = $store->getArray( $arrayId );
547568
 569+ // make sure at least an empty array exists if we return early
 570+ $store->setArray( $arrayId_new );
 571+
 572+ if( $array === null
 573+ || ! is_numeric( $offset ) // don't ignore invalid offset
 574+ ) {
 575+ return '';
 576+ }
548577
549 -
 578+ if( ! is_numeric( $length ) ) {
 579+ $length = null; // ignore invalid input, slice till end
 580+ }
 581+
 582+ // array_slice will re-organize keys
 583+ $newArray = array_slice( $array, $offset, $length );
 584+ $store->setArray( $arrayId_new, $newArray );
 585+
 586+ return '';
 587+ }
 588+
 589+
550590 ///////////////////////////////////////////////////////////
551 - // PART 3. alter an array
 591+ // PART 3. Array Alteration
552592 ///////////////////////////////////////////////////////////
553593
554594 /**
@@ -652,173 +692,150 @@
653693
654694
655695 ///////////////////////////////////////////////////////////
656 - // PART 4. create an array
 696+ // PART 4. Array Interaction
657697 ///////////////////////////////////////////////////////////
658 -
 698+
659699 /**
660 - * merge two arrays, keep duplicated values
661 - * usage:
662 - * {{#arraymerge:arrayid_new|arrayid1|arrayid2}}
663 - *
664 - * merge values two arrayes identified by arrayid1 and arrayid2 into a new array identified by arrayid_new.
665 - * this merge differs from array_merge of php because it merges values.
666 - */
667 - static function pf_arraymerge( Parser &$parser, $arrayId_new, $arrayId1 = null, $arrayId2 = null ) {
668 - if( ! isset( $arrayId_new ) || ! isset( $arrayId1 ) || ! isset( $arrayId2 ) ) {
669 - return '';
670 - }
671 - $store = self::get( $parser );
672 -
673 - $ret = $store->validate_array_by_arrayId( $arrayId1 );
674 - if( $ret !== true ) {
675 - return '';
676 - }
677 -
678 - $temp_array = array();
679 - foreach( $store->mArrays[ $arrayId1 ] as $entry ) {
680 - array_push ( $temp_array, $entry );
681 - }
682 -
683 - if( isset( $arrayId2 ) && strlen( $arrayId2 ) > 0 ) {
684 - $ret = $store->validate_array_by_arrayId( $arrayId2 );
685 - if( $ret === true ) {
686 - foreach( $store->mArrays[ $arrayId2 ] as $entry ) {
687 - array_push ( $temp_array, $entry );
688 - }
689 - }
690 - }
691 -
692 - $store->mArrays[$arrayId_new] = $temp_array;
693 - return '';
694 - }
695 -
696 - /**
697 - * extract a slice from an array
698 - * usage:
699 - * {{#arrayslice:arrayid_new|arrayid|offset|length}}
700 - *
701 - * extract a slice from an array
702 - * see: http://www.php.net/manual/en/function.array-slice.php
703 - */
704 - static function pf_arrayslice( Parser &$parser, $arrayId_new, $arrayId = null , $offset = 0, $length = null ) {
705 - $store = self::get( $parser );
706 - if( $arrayId === null ) {
707 - global $egArrayExtensionCompatbilityMode;
708 - if( ! $egArrayExtensionCompatbilityMode ) { // COMPATBILITY-MODE
709 - $store->setArray( $arrayId_new );
710 - }
711 - return '';
712 - }
713 - // get target array before overwriting it in any way
714 - $array = $store->getArray( $arrayId );
715 -
716 - // make sure at least an empty array exists if we return early
717 - $store->setArray( $arrayId_new );
718 -
719 - if( $array === null
720 - || ! is_numeric( $offset ) // don't ignore invalid offset
721 - ) {
722 - return '';
723 - }
724 -
725 - if( ! is_numeric( $length ) ) {
726 - $length = null; // ignore invalid input, slice till end
727 - }
728 -
729 - // array_slice will re-organize keys
730 - $newArray = array_slice( $array, $offset, $length );
731 - $store->setArray( $arrayId_new, $newArray );
732 -
 700+ * Merge values two arrayes identified by arrayid1 and arrayid2 into a new array identified by arrayid_new.
 701+ * This merge differs from array_merge of php because it merges values.
 702+ *
 703+ * Usage:
 704+ * {{#arraymerge:arrayid_new |array1 |array2 |... |array n}}
 705+ * See: http://www.php.net/manual/en/function.array-merge.php
 706+ */
 707+ static function pfObj_arraymerge( &$parser, $frame, $args) {
 708+ self::get( $parser )->multiArrayOperation( $frame, $args, __FUNCTION__, false );
733709 return '';
734710 }
735 -
736 - ///////////////////////////////////////////////// /
737 - // SET OPERATIONS: a set does not have duplicated element
 711+ private function multi_arraymerge( $array1, $array2 ) {
 712+ // keys will not be re-organized
 713+ return array_merge( $array1, $array2 );
 714+ }
738715
739 - /**
740 - * set operation, {red, white} = {red, white} union {red}
741 - * usage:
742 - * {{#arrayunion:arrayid_new|arrayid1|arrayid2}}
743 -
744 - * similar to arraymerge, this union works on values.
745 - */
746 - static function pf_arrayunion( Parser &$parser, $arrayId_new, $arrayId1 = null , $arrayId2 = null ) {
747 - $store = self::get( $parser );
748 - if ( ! isset( $arrayId_new ) || ! isset( $arrayId1 ) || ! isset( $arrayId2 ) ) {
749 - return '';
750 - }
751 - if( ! isset( $arrayId1 ) || ! $store->arrayExists( $arrayId1 ) ) {
752 - return '';
753 - }
754 - if( ! isset( $arrayId2 ) || ! $store->arrayExists( $arrayId2 ) ) {
755 - return '';
756 - }
757 -
758 - self::pf_arraymerge( $parser, $arrayId_new, $arrayId1, $arrayId2 );
759 - $store->setArray( $arrayId_new, array_unique ( $store->getArray( $arrayId_new ) ) );
760 -
761 - return '';
762 - }
 716+ /**
 717+ * Usage:
 718+ * {{#arrayunion:arrayid_new|arrayid1|arrayid2}}
 719+ *
 720+ * Set operation, {red, white} = {red, white} union {red}
 721+ * Similar to arraymerge but with unique values. This union works on values.
 722+ */
 723+ static function pfObj_arrayunion( &$parser, $frame, $args) {
 724+ self::get( $parser )->multiArrayOperation( $frame, $args, __FUNCTION__, false );
 725+ return '';
 726+ }
 727+ private function multi_arrayunion( $array1, $array2 ) {
 728+ // keys will not be re-organized
 729+ return array_unique( array_merge( $array1, $array2 ) );
 730+ }
763731
764732 /**
765 - * set operation, {red} = {red, white} intersect {red,black}
766 - * usage:
767 - * {{#arrayintersect:arrayid_new|arrayid1|arrayid2}}
768 - * See: http://www.php.net/manual/en/function.array-intersect.php
769 - */
770 - static function pf_arrayintersect( Parser &$parser, $arrayId_new, $arrayId1 = null , $arrayId2 = null ) {
771 - $store = self::get( $parser );
772 - if ( ! isset( $arrayId_new ) || ! isset( $arrayId1 ) || ! isset( $arrayId2 ) ) {
773 - return '';
774 - }
775 - if( ! isset( $arrayId1 ) || ! $store->arrayExists( $arrayId1 ) ) {
776 - return '';
777 - }
778 - if( ! isset( $arrayId2 ) || ! $store->arrayExists( $arrayId2 ) ) {
779 - return '';
780 - }
 733+ * Usage:
 734+ * {{#arrayintersect:arrayid_new |array1 |array2 |... |array n}}
 735+ *
 736+ * Set operation, {red} = {red, white} intersect {red,black}
 737+ * See: http://www.php.net/manual/en/function.array-intersect.php
 738+ */
 739+ static function pfObj_arrayintersect( &$parser, $frame, $args) {
 740+ self::get( $parser )->multiArrayOperation( $frame, $args, __FUNCTION__, false );
 741+ return '';
 742+ }
 743+ private function multi_arrayintersect( $array1, $array2 ) {
 744+ // keys will be preserved!
 745+ return array_intersect( $array1, $array2 );
 746+ }
781747
782 - // keys will be preserved...
783 - $newArray = array_intersect( array_unique( $store->mArrays[$arrayId1] ), array_unique( $store->mArrays[$arrayId2] ) );
784 -
785 - // ...so we have to reorganize the key order
786 - $store->mArrays[$arrayId_new] = self::sanitizeArray( $newArray );
787 -
788 - return '';
789 - }
790 -
791748 /**
792 - *
793 - * usage:
794 - * {{#arraydiff:arrayid_new|arrayid1|arrayid2}}
795 - *
796 - * set operation, {white} = {red, white} - {red}
797 - * see: http://www.php.net/manual/en/function.array-diff.php
798 - */
799 - static function pf_arraydiff( Parser &$parser, $arrayId_new, $arrayId1 = null , $arrayId2 = null ) {
800 - $store = self::get( $parser );
801 - if( ! isset( $arrayId_new ) || ! isset( $arrayId1 ) || ! isset( $arrayId2 ) ) {
802 - return '';
803 - }
804 - if( ! isset( $arrayId1 ) || ! $store->arrayExists( $arrayId1 ) ) {
805 - return '';
806 - }
807 - if( ! isset( $arrayId2 ) || ! $store->arrayExists( $arrayId2 ) ) {
808 - return '';
809 - }
810 - // keys will be preserved...
811 - $newArray = array_diff( array_unique( $store->mArrays[$arrayId1] ), array_unique( $store->mArrays[$arrayId2] ) );
812 -
813 - // ...so we have to reorganize the key order
814 - $store->mArrays[$arrayId_new] = self::sanitizeArray( $newArray );
815 -
816 - return '';
817 - }
 749+ *
 750+ * Usage:
 751+ * {{#arraydiff:arrayid_new |array1 |array2 |... |array n}}
 752+ *
 753+ * Set operation, {white} = {red, white} - {red}
 754+ * See: http://www.php.net/manual/en/function.array-diff.php
 755+ */
 756+ static function pfObj_arraydiff( &$parser, $frame, $args) {
 757+ self::get( $parser )->multiArrayOperation( $frame, $args, __FUNCTION__, false );
 758+ return '';
 759+ }
 760+ private function multi_arraydiff( $array1, $array2 ) {
 761+ // keys will be preserved!
 762+ return array_diff( $array1, $array2 );
 763+ }
818764
819765
820766 ##################
821767 # Private helper #
822768 ##################
 769+
 770+ /**
 771+ * Base function for operations with multiple arrays given thru n parameters
 772+ * $operationFunc expects a function name prefix (suffix 'multi_') with two parameters
 773+ * $array1 and $array2 which will perform an action between $array1 and $array2 which
 774+ * will result into a new $array1. There can be 1 to n $hash2 in the whole process.
 775+ *
 776+ * Note: This function is similar to that of Extension:HashTables.
 777+ *
 778+ * @since 2.0
 779+ *
 780+ * @param $frame PPFrame
 781+ * @param $args array
 782+ * @param $operationFunc string name of the function calling this. There must be a counterpart
 783+ * function with prefix 'multi_' which should have two parameters. Both parameters
 784+ * will receive an array, the function must return the result array of the processing.
 785+ * @param $runFuncOnSingleArray boolean whether the $operationFunc function should be run in case
 786+ * only one array id is given. If not, the original array will end up in the new array.
 787+ */
 788+ protected function multiArrayOperation( PPFrame $frame, array $args, $operationFunc, $runFuncOnSingleArray = true ) {
 789+ $lastArray = null;
 790+ $operationRan = false;
 791+ $finalArrayId = trim( $frame->expand( $args[0] ) );
 792+ $operationFunc = 'multi_' . preg_replace( '/^pfObj_/', '', $operationFunc );
 793+
 794+ // For all arrays given in parameters 2 to n (ignore 1 because this is the name of the new array)
 795+ for( $i = 1; $i < count( $args ); $i++ ) {
 796+ // just make sure we don't fall into gaps of given arguments:
 797+ if( ! array_key_exists( $i, $args ) ) {
 798+ continue;
 799+ }
 800+ $argArrayId = trim( $frame->expand( $args[ $i ] ) );
 801+
 802+ // ignore all tables which do not exist
 803+ if( $this->arrayExists( $argArrayId ) ) {
 804+ $argArray = $this->getArray( $argArrayId );
 805+ if( $lastArray === null ) {
 806+ // first valid array, process together with second...
 807+ $lastArray = $argArray;
 808+ }
 809+ else {
 810+ // second or later hash table, process with previous:
 811+ $lastArray = $this->{ $operationFunc }( $lastArray, $argArray ); // perform action between last and current array
 812+ $operationRan = true;
 813+ }
 814+ }
 815+ }
 816+
 817+ // in case no array was given at all:
 818+ if( $lastArray === null ) {
 819+ $lastArray = array();
 820+ }
 821+
 822+ global $egArrayExtensionCompatbilityMode;
 823+
 824+ if( ! $operationRan && $egArrayExtensionCompatbilityMode ) {
 825+ // COMPATBILITY-MODE:
 826+ // Before version 2.0 we didn't create a new array in case only one array was given
 827+ return '';
 828+ }
 829+
 830+ // if the operation didn't run because there was only one or no array:
 831+ if( ! $operationRan && $runFuncOnSingleArray ) {
 832+ $lastArray = $this->{ $operationFunc }( $lastArray );
 833+ }
 834+
 835+ // re-organize all keys since some 'multi_' functions will preserve keys!
 836+ $lastArray = array_merge( $lastArray );
 837+
 838+ $this->setArray( $finalArrayId, $lastArray );
 839+ }
823840
824841 /**
825842 * Validates an index for an array and returns true in case the index is a valid index within
Index: trunk/extensions/ArrayExtension/RELEASE-NOTES
@@ -5,11 +5,14 @@
66 This release is built upon 1.4 alpha. See changes of 1.4 alpha as well.
77 - class 'ArrayExtension' renamed to 'ExtArrayExtension'
88 - '#arrayindex' will only expand options/default when required.
 9+ - '#arraymerge', '#arrayunion', '#arraydiff' and '#arrayintersect' can handle multiple arrays now.
910 - Compatbility mode variable '$egArrayExtensionCompatbilityMode' is set to false by default. See
1011 Version 1.4 alpha for further information. Further changes to the compatbility mode behavior
1112 in version 2.0:
1213 + '#arrayindex' will return its default also in case of existing index but empty value. This
1314 makes the function consistent with Variables '#var' and hash tables '#hashvalue'.
 15+ + '#arraymerge', '#arrayunion', '#arraydiff' and '#arrayintersect' with only one array for
 16+ the operation will make a copy of that array instead of creating no array at all.
1417 + See 1.4 alpha for previous changes
1518
1619

Status & tagging log