Completed
Push — master ( bca71a...3af5ad )
by Sandro
06:14 queued 02:11
created

ConfigurationTrait::canRetrieveOptions()   C

Complexity

Conditions 12
Paths 12

Size

Total Lines 23
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 13
CRAP Score 12

Importance

Changes 5
Bugs 1 Features 1
Metric Value
c 5
b 1
f 1
dl 0
loc 23
rs 5.2987
ccs 13
cts 13
cp 1
cc 12
eloc 13
nc 12
nop 2
crap 12

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * Sandro Keil (https://sandro-keil.de)
4
 *
5
 * @link      http://github.com/sandrokeil/interop-config for the canonical source repository
6
 * @copyright Copyright (c) 2015-2016 Sandro Keil
7
 * @license   http://github.com/sandrokeil/interop-config/blob/master/LICENSE.md New BSD License
8
 */
9
10
namespace Interop\Config;
11
12
use ArrayAccess;
13
use Interop\Config\Exception;
14
15
/**
16
 * ConfigurationTrait which retrieves options from configuration, see interface \Interop\Config\RequiresConfig
17
 *
18
 * This trait is a implementation of \Interop\Config\RequiresConfig. Retrieves options from a configuration and optional
19
 * to perform a mandatory option check. Default options are merged and overridden of the provided options.
20
 */
21
trait ConfigurationTrait
22
{
23
    /**
24
     * @inheritdoc \Interop\Config\RequiresConfig::dimensions
25
     */
26
    abstract public function dimensions();
27
28
    /**
29
     * Checks if options are available depending on implemented interfaces and checks that the retrieved options are an
30
     * array or have implemented \ArrayAccess.
31
     *
32
     * The RequiresConfigId interface is supported.
33
     *
34
     * @param array|ArrayAccess $config Configuration
35
     * @param string|null $configId Config name, must be provided if factory uses RequiresConfigId interface
36
     * @return bool True if options are available, otherwise false
37
     */
38 24
    public function canRetrieveOptions($config, $configId = null)
39
    {
40 24
        $dimensions = $this->dimensions();
41
42 24
        if ($this instanceof RequiresConfigId) {
43 13
            $dimensions[] = $configId;
44
        }
45
46 24
        foreach ($dimensions as $dimension) {
47 23
            if ((!is_array($config) && !$config instanceof ArrayAccess)
48 23
                || (!isset($config[$dimension]) && $this instanceof RequiresMandatoryOptions)
49 23
                || (!isset($config[$dimension]) && !$this instanceof ProvidesDefaultOptions)
50
            ) {
51 10
                return false;
52
            }
53 22
            if (!isset($config[$dimension]) && $this instanceof ProvidesDefaultOptions) {
54 1
                return true;
55
            }
56
57 21
            $config = $config[$dimension];
58
        }
59 16
        return is_array($config) || $config instanceof ArrayAccess;
60
    }
61
62
    /**
63
     * Returns options based on dimensions() like [vendor][package] and can perform mandatory option checks if
64
     * class implements RequiresMandatoryOptions. If the ProvidesDefaultOptions interface is implemented, these options
65
     * must be overridden by the provided config. If you want to allow configurations for more then one instance use
66
     * RequiresConfigId interface.
67
     *
68
     * The RequiresConfigId interface is supported.
69
     *
70
     * @param array|ArrayAccess $config Configuration
71
     * @param string $configId Config name, must be provided if factory uses RequiresConfigId interface
72
     * @return array|ArrayAccess
73
     * @throws Exception\InvalidArgumentException If the $configId parameter is provided but factory does not support it
74
     * @throws Exception\UnexpectedValueException If the $config parameter has the wrong type
75
     * @throws Exception\OptionNotFoundException If no options are available
76
     * @throws Exception\MandatoryOptionNotFoundException If a mandatory option is missing
77
     */
78 21
    public function options($config, $configId = null)
79
    {
80 21
        $options = $config;
81 21
        $dimensions = $this->dimensions();
82
83 21
        if ($this instanceof RequiresConfigId) {
84 10
            $dimensions[] = $configId;
85 11
        } elseif ($configId !== null) {
86 1
            throw new Exception\InvalidArgumentException(
87 1
                sprintf('The factory "%s" does not support multiple instances.', __CLASS__)
88
            );
89
        }
90
91
        // get configuration for provided dimensions
92 20
        foreach ($dimensions as $dimension) {
93 19
            if (!is_array($options) && !$options instanceof ArrayAccess) {
94 1
                throw Exception\UnexpectedValueException::invalidOptions($dimensions, $dimension);
95
            }
96
97 19
            if (!isset($options[$dimension])) {
98 7
                if (!$this instanceof RequiresMandatoryOptions && $this instanceof ProvidesDefaultOptions) {
99 1
                    break;
100
                }
101 6
                throw Exception\OptionNotFoundException::missingOptions($this, $dimension, $configId);
102
            }
103 17
            $options = $options[$dimension];
104
        }
105
106 13
        if (!is_array($options) && !$options instanceof ArrayAccess) {
107 1
            throw Exception\UnexpectedValueException::invalidOptions($this->dimensions());
108
        }
109
110 12
        if ($this instanceof RequiresMandatoryOptions) {
111 7
            $this->checkMandatoryOptions($this->mandatoryOptions(), $options);
112
        }
113
114 10
        if ($this instanceof ProvidesDefaultOptions) {
115 3
            $options = array_replace_recursive($this->defaultOptions(), $options);
116
        }
117 10
        return $options;
118
    }
119
120
    /**
121
     * Checks if options can be retrieved from config and if not, default options (ProvidesDefaultOptions interface) or
122
     * an empty array will be returned.
123
     *
124
     * @param array|ArrayAccess $config Configuration
125
     * @param string $configId Config name, must be provided if factory uses RequiresConfigId interface
126
     * @return array|ArrayAccess options Default options or an empty array
127
     */
128 1
    public function optionsWithFallback($config, $configId = null)
129
    {
130 1
        $options = [];
131
132 1
        if ($this->canRetrieveOptions($config, $configId)) {
133 1
            $options = $this->options($config, $configId);
134
        }
135 1
        if (empty($options) && $this instanceof ProvidesDefaultOptions) {
136 1
            $options = $this->defaultOptions();
137
        }
138 1
        return $options;
139
    }
140
141
    /**
142
     * Checks if a mandatory param is missing, supports recursion
143
     *
144
     * @param array|ArrayAccess $mandatoryOptions
145
     * @param array|ArrayAccess $options
146
     * @throws Exception\MandatoryOptionNotFoundException
147
     */
148 6
    private function checkMandatoryOptions($mandatoryOptions, $options)
0 ignored issues
show
Unused Code introduced by
This method is not used, and could be removed.
Loading history...
149
    {
150 6
        foreach ($mandatoryOptions as $key => $mandatoryOption) {
151 6
            $useRecursion = !is_scalar($mandatoryOption);
152
153 6
            if ($useRecursion && isset($options[$key])) {
154 2
                $this->checkMandatoryOptions($mandatoryOption, $options[$key]);
155 1
                return;
156
            }
157
158 6
            if (!$useRecursion && isset($options[$mandatoryOption])) {
159 5
                continue;
160
            }
161
162 3
            throw Exception\MandatoryOptionNotFoundException::missingOption(
163 3
                $this->dimensions(),
164 3
                $useRecursion ? $key : $mandatoryOption
165
            );
166
        }
167 3
    }
168
}
169