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