Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
MergeStrategy
100.00% covered (success)
100.00%
28 / 28
100.00% covered (success)
100.00%
5 / 5
15
100.00% covered (success)
100.00%
1 / 1
 newFromName
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 __construct
100.00% covered (success)
100.00%
2 / 2
100.00% covered (success)
100.00%
1 / 1
1
 getName
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 merge
100.00% covered (success)
100.00%
19 / 19
100.00% covered (success)
100.00%
1 / 1
9
 reverse
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
1<?php
2
3namespace MediaWiki\Settings\Config;
4
5use MediaWiki\Settings\SettingsBuilderException;
6use function array_key_exists;
7
8class 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}