Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
22 / 22
100.00% covered (success)
100.00%
5 / 5
CRAP
100.00% covered (success)
100.00%
1 / 1
MergeStrategy
100.00% covered (success)
100.00%
22 / 22
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%
13 / 13
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 Wikimedia\ArrayUtils\ArrayUtils;
7use function array_key_exists;
8
9class 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}