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    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}