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