Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
| Total | |
100.00% |
22 / 22 |
|
100.00% |
5 / 5 |
CRAP | |
100.00% |
1 / 1 |
| MergeStrategy | |
100.00% |
22 / 22 |
|
100.00% |
5 / 5 |
15 | |
100.00% |
1 / 1 |
| newFromName | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
| __construct | |
100.00% |
2 / 2 |
|
100.00% |
1 / 1 |
1 | |||
| getName | |
100.00% |
1 / 1 |
|
100.00% |
1 / 1 |
1 | |||
| merge | |
100.00% |
13 / 13 |
|
100.00% |
1 / 1 |
9 | |||
| reverse | |
100.00% |
3 / 3 |
|
100.00% |
1 / 1 |
2 | |||
| 1 | <?php |
| 2 | |
| 3 | namespace MediaWiki\Settings\Config; |
| 4 | |
| 5 | use MediaWiki\Settings\SettingsBuilderException; |
| 6 | use Wikimedia\ArrayUtils\ArrayUtils; |
| 7 | use function array_key_exists; |
| 8 | |
| 9 | class MergeStrategy { |
| 10 | |
| 11 | public const ARRAY_MERGE_RECURSIVE = 'array_merge_recursive'; |
| 12 | public const ARRAY_REPLACE_RECURSIVE = 'array_replace_recursive'; |
| 13 | public const ARRAY_PLUS_2D = 'array_plus_2d'; |
| 14 | public const ARRAY_PLUS = 'array_plus'; |
| 15 | public const ARRAY_MERGE = 'array_merge'; |
| 16 | public const REPLACE = 'replace'; |
| 17 | |
| 18 | /** @var string */ |
| 19 | private $name; |
| 20 | |
| 21 | /** @var bool */ |
| 22 | private $reversed; |
| 23 | |
| 24 | /** @var MergeStrategy[] */ |
| 25 | private static $strategies = []; |
| 26 | |
| 27 | /** @var MergeStrategy[] */ |
| 28 | private static $reversedStrategies = []; |
| 29 | |
| 30 | /** |
| 31 | * @param string $name |
| 32 | * @return self |
| 33 | */ |
| 34 | public static function newFromName( string $name ): self { |
| 35 | if ( !array_key_exists( $name, self::$strategies ) ) { |
| 36 | self::$strategies[$name] = new MergeStrategy( $name ); |
| 37 | } |
| 38 | return self::$strategies[$name]; |
| 39 | } |
| 40 | |
| 41 | /** |
| 42 | * @param string $name |
| 43 | * @param bool $reversed |
| 44 | */ |
| 45 | private function __construct( string $name, bool $reversed = false ) { |
| 46 | $this->name = $name; |
| 47 | $this->reversed = $reversed; |
| 48 | } |
| 49 | |
| 50 | public function getName(): string { |
| 51 | return $this->name; |
| 52 | } |
| 53 | |
| 54 | /** |
| 55 | * Merge $source into $destination. |
| 56 | * |
| 57 | * @note For all merge strategies except self::ARRAY_MERGE_RECURSIVE, |
| 58 | * for the values that have the same key, the value from $source will |
| 59 | * override the value in the $destination. |
| 60 | * |
| 61 | * @param array $destination |
| 62 | * @param array $source |
| 63 | * @return array |
| 64 | */ |
| 65 | public function merge( array $destination, array $source ): array { |
| 66 | if ( $this->reversed ) { |
| 67 | [ $destination, $source ] = [ $source, $destination ]; |
| 68 | } |
| 69 | |
| 70 | switch ( $this->name ) { |
| 71 | case self::REPLACE: |
| 72 | return $source; |
| 73 | case self::ARRAY_MERGE_RECURSIVE: |
| 74 | return array_merge_recursive( $destination, $source ); |
| 75 | case self::ARRAY_REPLACE_RECURSIVE: |
| 76 | return array_replace_recursive( $destination, $source ); |
| 77 | case self::ARRAY_PLUS_2D: |
| 78 | return ArrayUtils::arrayPlus2d( $source, $destination ); |
| 79 | case self::ARRAY_PLUS: |
| 80 | return $source + $destination; |
| 81 | case self::ARRAY_MERGE: |
| 82 | return array_merge( $destination, $source ); |
| 83 | default: |
| 84 | throw new SettingsBuilderException( |
| 85 | 'Unknown merge strategy {name}', |
| 86 | [ 'name' => $this->name ] |
| 87 | ); |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | /** |
| 92 | * Create a reversed merge strategy, which will merge $destination into $source |
| 93 | * instead of $source into $destination. |
| 94 | * |
| 95 | * @see self::merge |
| 96 | * @return MergeStrategy |
| 97 | */ |
| 98 | public function reverse(): self { |
| 99 | if ( !array_key_exists( $this->name, self::$reversedStrategies ) ) { |
| 100 | self::$reversedStrategies[$this->name] = new self( $this->name, !$this->reversed ); |
| 101 | } |
| 102 | return self::$reversedStrategies[$this->name]; |
| 103 | } |
| 104 | } |