Config   A
last analyzed

Complexity

Total Complexity 19

Size/Duplication

Total Lines 117
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 53
c 1
b 0
f 0
dl 0
loc 117
rs 10
wmc 19

6 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 60 11
A offsetGet() 0 7 2
A offsetSet() 0 3 1
A offsetUnset() 0 7 2
A count() 0 3 1
A offsetExists() 0 7 2
1
<?php declare(strict_types=1);
2
3
/*
4
 * This file is part of Biurad opensource projects.
5
 *
6
 * @copyright 2022 Biurad Group (https://biurad.com/)
7
 * @license   https://opensource.org/licenses/BSD-3-Clause License
8
 *
9
 * For the full copyright and license information, please view the LICENSE
10
 * file that was distributed with this source code.
11
 */
12
13
namespace Biurad\Monorepo;
14
15
use Symfony\Component\OptionsResolver\Exception\{AccessException, InvalidOptionsException};
16
use Symfony\Component\OptionsResolver\{Options, OptionsResolver};
17
use Symfony\Component\Yaml\Yaml;
18
19
/**
20
 * Monorepo configuration (.monorepo).
21
 *
22
 * @author Divine Niiquaye Ibok <[email protected]>
23
 */
24
final class Config implements \ArrayAccess, \Countable
25
{
26
    /** @var array<string,mixed> */
27
    private array $config;
28
29
    public function __construct(string $rootPath, string $cachePath = null, bool $reclone)
30
    {
31
        if (!\file_exists($configFile = ($this->config['path'] = $rootPath).'/.monorepo')) {
32
            throw new \RuntimeException(\sprintf('Config file "%s" does not exist.', $configFile));
33
        }
34
35
        $workers = [];
36
        $this->config['reclone'] = $reclone;
37
        $options = new OptionsResolver();
38
        $options
39
            ->define('base_url')->default(null)->allowedTypes('string', 'null')
40
            ->define('branch_filter')->default(null)->allowedTypes('string', 'null')
41
            ->define('extra')->default([])->allowedTypes('array')
42
            ->define('workers')->default([])->allowedTypes('array')
43
            ->normalize(function (Options $options, array $value): array {
44
                if (\array_is_list($value)) {
0 ignored issues
show
Bug introduced by
The function array_is_list was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

44
                if (/** @scrutinizer ignore-call */ \array_is_list($value)) {
Loading history...
45
                    return ['main' => $value];
46
                }
47
48
                foreach ($value as $k => $v) {
49
                    $v = \is_string($v) ? [$v] : $v;
50
51
                    if (!\is_string($k)) {
52
                        throw new InvalidOptionsException('Expected workers config to begin with a string key.');
53
                    }
54
55
                    if (!\is_array($v) || !\array_is_list($v)) {
56
                        throw new InvalidOptionsException('Expected workers config\'s key value be a list of workers classes.');
57
                    }
58
                }
59
60
                return $value;
61
            })
62
            ->define('repositories')
63
            ->default(function (OptionsResolver $options, Options $parent) use (&$workers): void {
64
                $workers = \array_keys($parent['workers']);
65
                $options->setPrototype(true)
66
                    ->define('url')->default(null)->allowedTypes('string', 'null')->required()
67
                    ->define('merge')->default(false)->allowedTypes('bool')
68
                    ->define('path')
69
                    ->allowedTypes('string')
70
                    ->default(\Closure::bind(fn (Options $options): string => $options->prototypeIndex, null, $options))
0 ignored issues
show
Bug introduced by
Accessing prototypeIndex on the interface Symfony\Component\OptionsResolver\Options suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
71
                    ->normalize(fn (Options $options, string $value): string => \trim($value, '/'))
72
                    ->define('workers')->default($workers)->allowedTypes('array')
73
                    ->normalize(function (Options $options, array $value) use ($workers): array {
74
                        foreach ($value as $worker) {
75
                            if (!\in_array($worker, $workers, true)) {
76
                                throw new InvalidOptionsException(\sprintf('The worker "%s" for monorepo\'s path "%s" does not exist.', $worker, $options['path']));
77
                            }
78
                        }
79
80
                        return $value;
81
                    })
82
                ;
83
            })->allowedTypes('array')
84
        ;
85
86
        $options->setRequired(['base_url', 'branch_filter', 'workers', 'repositories']);
87
        $this->config += $options->resolve(\function_exists('yaml_parse_file') ? yaml_parse_file($configFile) : Yaml::parseFile($configFile));
88
        $this->config['cache'] = $cachePath ?? $this->config['path'].'/.monorepo-cache';
89
    }
90
91
    /**
92
     * {@inheritdoc}
93
     */
94
    public function offsetGet(mixed $offset): mixed
95
    {
96
        if (!\is_string($offset)) {
97
            throw new InvalidOptionsException(\sprintf('Expected a string key, got a type of "%s" instead.', \get_debug_type($offset)));
98
        }
99
100
        return $this->config[$offset] ?? throw new InvalidOptionsException(\sprintf('Value for "%s" does not exist.', $offset));
101
    }
102
103
    /**
104
     * {@inheritdoc}
105
     */
106
    public function offsetExists(mixed $offset): bool
107
    {
108
        if (!\is_string($offset)) {
109
            throw new InvalidOptionsException(\sprintf('Expected a string key, got a type of "%s" instead.', \get_debug_type($offset)));
110
        }
111
112
        return \array_key_exists($offset, $this->config);
113
    }
114
115
    /**
116
     * {@inheritdoc}
117
     */
118
    public function offsetSet(mixed $offset, mixed $value): void
119
    {
120
        throw new AccessException('Unexpected call for setting config, kindly define config in the .monorepo file.');
121
    }
122
123
    /**
124
     * {@inheritdoc}
125
     */
126
    public function offsetUnset(mixed $offset): void
127
    {
128
        if (!\is_string($offset)) {
129
            throw new InvalidOptionsException(\sprintf('Expected a string key, got a type of "%s" instead.', \get_debug_type($offset)));
130
        }
131
132
        unset($this->config[$offset]);
133
    }
134
135
    /**
136
     * {@inheritdoc}
137
     */
138
    public function count(): int
139
    {
140
        return \count($this->config);
141
    }
142
}
143