GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Config   B
last analyzed

Complexity

Total Complexity 44

Size/Duplication

Total Lines 239
Duplicated Lines 0 %

Test Coverage

Coverage 61.68%

Importance

Changes 0
Metric Value
eloc 103
c 0
b 0
f 0
dl 0
loc 239
ccs 66
cts 107
cp 0.6168
rs 8.8798
wmc 44

11 Methods

Rating   Name   Duplication   Size   Complexity  
A calculateEntitiesPath() 0 9 2
B get() 0 30 8
A calculateMigrationsDirectory() 0 8 4
A getUnderscoreNamingStrategy() 0 3 1
A calculateEntitiesCustomDataPath() 0 9 2
B validateConfig() 0 32 9
A __construct() 0 19 5
A getProjectRootDirectory() 0 14 3
A getFilesystemCachePath() 0 8 4
A calculateProjectRootNamespace() 0 5 1
A calculateProxyDir() 0 16 5

How to fix   Complexity   

Complex Class

Complex classes like Config often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Config, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
declare(strict_types=1);
4
5
namespace EdmondsCommerce\DoctrineStaticMeta;
6
7
use Composer\Autoload\ClassLoader;
8
use Doctrine\ORM\Mapping\UnderscoreNamingStrategy;
9
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\NamespaceHelper;
10
use EdmondsCommerce\DoctrineStaticMeta\CodeGeneration\TypeHelper;
11
use EdmondsCommerce\DoctrineStaticMeta\Exception\ConfigException;
12
use EdmondsCommerce\DoctrineStaticMeta\Exception\DoctrineStaticMetaException;
13
use Exception;
14
use RuntimeException;
15
use ts\Reflection\ReflectionClass;
16
17
use function array_key_exists;
18
use function dirname;
19
use function get_class;
20
use function in_array;
21
use function is_object;
22
23
/**
24
 * Class Config
25
 *
26
 * @package EdmondsCommerce\DoctrineStaticMeta
27
 * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
28
 */
29
class Config implements ConfigInterface
30
{
31
32
    private static $projectRootDirectory;
33
    private $config = [];
34
35
    /**
36
     * Config constructor.
37
     *
38
     * @param array|mixed[] $server
39
     *
40
     * @throws ConfigException
41
     * @throws DoctrineStaticMetaException
42
     */
43 16
    public function __construct(array $server)
44
    {
45 16
        foreach (static::REQUIRED_PARAMS as $key) {
46 16
            if (!array_key_exists($key, $server)) {
47 4
                throw new ConfigException(
48 4
                    'required config param ' . $key . ' is not set in $server'
49
                );
50
            }
51 12
            $this->config[$key] = $server[$key];
52
        }
53 12
        foreach (self::PARAMS as $key) {
54 12
            if (array_key_exists($key, $server)) {
55 12
                $this->config[$key] = $server[$key];
56 12
                continue;
57
            }
58 12
            $this->config[$key] = $this->get($key);
59
        }
60
61 12
        $this->validateConfig();
62 12
    }
63
64
    /**
65
     * @param string $key
66
     * @param mixed  $default
67
     *
68
     * @return mixed|string
69
     * @throws DoctrineStaticMetaException
70
     */
71 12
    public function get(string $key, $default = ConfigInterface::NO_DEFAULT_VALUE)
72
    {
73
        if (
74 12
            !isset(static::REQUIRED_PARAMS[$key])
75 12
            && !isset(static::OPTIONAL_PARAMS_WITH_DEFAULTS[$key])
76 12
            && !isset(static::OPTIONAL_PARAMS_WITH_CALCULATED_DEFAULTS[$key])
77
        ) {
78
            throw new ConfigException(
79
                'Invalid config param '
80
                . $key
81
                . ', should be one of '
82
                . print_r(static::PARAMS, true)
83
            );
84
        }
85 12
        if (isset($this->config[$key])) {
86 12
            return $this->config[$key];
87
        }
88 12
        if (ConfigInterface::NO_DEFAULT_VALUE !== $default) {
89
            return $default;
90
        }
91 12
        if (isset(static::OPTIONAL_PARAMS_WITH_DEFAULTS[$key])) {
92 12
            return static::OPTIONAL_PARAMS_WITH_DEFAULTS[$key];
93
        }
94 12
        if (isset(static::OPTIONAL_PARAMS_WITH_CALCULATED_DEFAULTS[$key])) {
95 12
            $method = static::OPTIONAL_PARAMS_WITH_CALCULATED_DEFAULTS[$key];
96
97 12
            return $this->$method();
98
        }
99
        throw new ConfigException(
100
            'No config set for param ' . $key . ' and no default provided'
101
        );
102
    }
103
104
    /**
105
     * @throws ConfigException
106
     * @throws DoctrineStaticMetaException
107
     */
108 12
    private function validateConfig(): void
109
    {
110 12
        $errors     = [];
111 12
        $typeHelper = new TypeHelper();
112 12
        foreach (ConfigInterface::PARAM_TYPES as $param => $requiredType) {
113 12
            $value = $this->get($param);
114
            if (
115 12
                self::TYPE_BOOL === $requiredType
116 12
                && is_numeric($value)
117 12
                && in_array((int)$value, [0, 1], true)
118
            ) {
119 2
                $this->config[$param] = ($value === 1);
120 2
                continue;
121
            }
122 12
            if (is_object($value)) {
123 12
                if (!($value instanceof $requiredType)) {
124
                    $actualType = get_class($value);
125
                    $errors[]   =
126
                        ' ERROR  ' . $param . ' is not an instance of the required object [' . $requiredType . ']'
127
                        . 'currently configured as an object of the class  [' . $actualType . ']';
128
                }
129 12
                continue;
130
            }
131 12
            $actualType = $typeHelper->getType($value);
132 12
            if ($actualType !== $requiredType) {
133
                $valueString = var_export($value, true);
134
                $errors[]    = ' ERROR  ' . $param . ' is not of the required type [' . $requiredType . ']'
135
                               . ' currently configured as type [' . $actualType . '] with value: ' . $valueString;
136
            }
137
        }
138 12
        if ([] !== $errors) {
139
            throw new ConfigException(implode("\n\n", $errors));
140
        }
141 12
    }
142
143
    /**
144
     * Default Entities path, calculated default
145
     *
146
     * @return string
147
     * @throws DoctrineStaticMetaException
148
     */
149 10
    private function calculateEntitiesPath(): string
150
    {
151
        try {
152 10
            return self::getProjectRootDirectory() . '/src/Entities';
153
        } catch (Exception $e) {
154
            throw new DoctrineStaticMetaException(
155
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
156
                $e->getCode(),
157
                $e
158
            );
159
        }
160
    }
161
162 12
    private function calculateEntitiesCustomDataPath(): string
163
    {
164
        try {
165 12
            return self::getProjectRootDirectory() . '/tests/Assets/Entity/FakerDataFillers';
166
        } catch (Exception $e) {
167
            throw new DoctrineStaticMetaException(
168
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
169
                $e->getCode(),
170
                $e
171
            );
172
        }
173
    }
174
175
    /**
176
     * Get the absolute path to the root of the current project
177
     *
178
     * It does this by working from the Composer autoloader which we know will be in a certain place in `vendor`
179
     *
180
     * @return string
181
     * @throws DoctrineStaticMetaException
182
     */
183 12
    public static function getProjectRootDirectory(): string
184
    {
185
        try {
186 12
            if (null === self::$projectRootDirectory) {
187
                $reflection                 = new ReflectionClass(ClassLoader::class);
188
                self::$projectRootDirectory = dirname($reflection->getFileName(), 3);
189
            }
190
191 12
            return self::$projectRootDirectory;
192
        } catch (Exception $e) {
193
            throw new DoctrineStaticMetaException(
194
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
195
                $e->getCode(),
196
                $e
197
            );
198
        }
199
    }
200
201
    /**
202
     * Default Entities path, calculated default
203
     *
204
     * @return string
205
     * @throws DoctrineStaticMetaException
206
     */
207 12
    private function calculateProxyDir(): string
208
    {
209
        try {
210 12
            $dir = self::getProjectRootDirectory() . '/cache/Proxies';
211 12
            if (!is_dir($dir) && !(mkdir($dir, 0777, true) && is_dir($dir))) {
212
                throw new RuntimeException(
213
                    'Proxy directory ' . $dir . ' does not exist and failed trying to create it'
214
                );
215
            }
216
217 12
            return $dir;
218
        } catch (Exception $e) {
219
            throw new DoctrineStaticMetaException(
220
                'Exception in ' . __METHOD__ . ': ' . $e->getMessage(),
221
                $e->getCode(),
222
                $e
223
            );
224
        }
225
    }
226
227
    /**
228
     * @return UnderscoreNamingStrategy
229
     */
230 12
    private function getUnderscoreNamingStrategy(): UnderscoreNamingStrategy
231
    {
232 12
        return new UnderscoreNamingStrategy();
233
    }
234
235
    /**
236
     * @return string
237
     * @throws DoctrineStaticMetaException
238
     */
239 12
    private function getFilesystemCachePath(): string
240
    {
241 12
        $path = self::getProjectRootDirectory() . '/cache/dsm';
242 12
        if (!is_dir($path) && !(mkdir($path, 0777, true) && is_dir($path))) {
243
            throw new RuntimeException('Failed creating default cache path at ' . $path);
244
        }
245
246 12
        return $path;
247
    }
248
249
    /**
250
     * @return string
251
     * @throws DoctrineStaticMetaException
252
     */
253 12
    private function calculateMigrationsDirectory(): string
254
    {
255 12
        $path = self::getProjectRootDirectory() . '/migrations';
256 12
        if (!is_dir($path) && !(mkdir($path, 0777, true) && is_dir($path))) {
257
            throw new RuntimeException('Failed creating default migrations directory at ' . $path);
258
        }
259
260 12
        return $path;
261
    }
262
263 12
    private function calculateProjectRootNamespace(): string
264
    {
265 12
        $namespaceHelper = new NamespaceHelper();
266
        
267 12
        return $namespaceHelper->getProjectRootNamespaceFromComposerJson();
268
    }
269
}
270