Passed
Push — 1.x ( 2c4985...95f1eb )
by Khairi
13:27
created

DatasourceConfigurator::evaluateConditions()   A

Complexity

Conditions 4
Paths 5

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 4

Importance

Changes 0
Metric Value
eloc 8
c 0
b 0
f 0
dl 0
loc 13
ccs 9
cts 9
cp 1
rs 10
cc 4
nc 5
nop 2
crap 4
1
<?php
2
3
namespace Khusseini\PimcoreRadBrickBundle\Configurator;
4
5
use ArrayObject;
6
use Khusseini\PimcoreRadBrickBundle\ContextInterface;
7
use Khusseini\PimcoreRadBrickBundle\DatasourceRegistry;
8
use Khusseini\PimcoreRadBrickBundle\RenderArgument;
9
use Khusseini\PimcoreRadBrickBundle\RenderArgumentEmitter;
10
use PHP_CodeSniffer\Config;
11
use Symfony\Component\OptionsResolver\OptionsResolver;
12
13
class DatasourceConfigurator extends AbstractConfigurator
14
{
15 7
    public function preCreateEditables(string $brickName, ConfiguratorData $data): void
16
    {
17 7
        $config = $this->resolveConfig($data->getConfig());
18 7
        $context = $data->getContext();
19 7
        $contextArray = $context->toArray();
20
21 7
        $brickConfig = $this->resolveBrickconfig($config['areabricks'][$brickName]);
22 7
        $registry = new DatasourceRegistry();
23 7
        foreach ($brickConfig['datasources'] as $id => $datasourceConfig) {
24 7
            $dsId = $datasourceConfig['id'];
25 7
            $dataSource = $config['datasources'][$dsId];
26 7
            $serviceId = $dataSource['service_id'];
27 7
            $serviceObject = null;
28
29 7
            if (\is_string($serviceId)) {
30
                $serviceObject = $this
31 7
                    ->getExpressionWrapper()
32 7
                    ->evaluateExpression($serviceId, $contextArray)
33
                ;
34
            }
35
36 7
            if (!\is_object($serviceObject)) {
37 1
                throw new \InvalidArgumentException(sprintf('Service with id "%s" is not an object. %s given.', $serviceId, \gettype($serviceObject)));
38
            }
39
40 6
            $dataCall = $registry->createMethodCall(
41 6
                $serviceObject,
42 6
                $dataSource['method'],
43 6
                $dataSource['args']
44
            );
45
46
            $wrappedCall = function () use ($context, $dataCall, $datasourceConfig) {
47 6
                return $this->callDatasource($context, $dataCall, $datasourceConfig);
48 6
            };
49
50 6
            $registry->add($id, $wrappedCall);
51
        }
52
53 6
        $data->getContext()->setDatasources($registry);
54 6
    }
55
56
    /**
57
     * @param array<string, array<string, mixed>> $config
58
     *
59
     * @return mixed
60
     */
61 6
    protected function callDatasource(ContextInterface $context, callable $dataCall, array $config)
62
    {
63 6
        $input = [];
64
        if (
65 6
                isset($config['conditions'])
66 6
                && \is_array($config['conditions'])
67 6
                && !$this->evaluateConditions($config['conditions'], $context)
68
        ) {
69 1
            return [];
70
        }
71
72 5
        foreach ($config['args'] as $name => $value) {
73 5
            $input[$name] = $this->recurseExpression($value, $context->toArray());
74
        }
75
76 5
        return $dataCall($input);
77
    }
78
79
    /**
80
     * @param string[] $conditions
81
     */
82 2
    protected function evaluateConditions(array $conditions, ContextInterface $context): bool
83
    {
84 2
        $result = false;
85 2
        $contextArray = $context->toArray();
86 2
        foreach ($conditions as $condition) {
87 2
            $value = $this->getExpressionWrapper()->evaluateExpression($condition, $contextArray);
88 2
            $result = ($value !== $condition) && (bool) $value;
89 2
            if (!$result) {
90 1
                return $result;
91
            }
92
        }
93
94 1
        return $result;
95
    }
96
97
    /**
98
     * @param mixed                $value
99
     * @param array<string, mixed> $context
100
     *
101
     * @return mixed
102
     */
103 5
    protected function recurseExpression($value, array $context)
104
    {
105 5
        if (\is_string($value)) {
106
            return $this
107 5
                ->getExpressionWrapper()
108 5
                ->evaluateExpression($value, $context);
109
        }
110
111 1
        if (\is_array($value)) {
112 1
            foreach ($value as $key => $item) {
113 1
                $value[$key] = $this->recurseExpression($item, $context);
114
            }
115
        }
116
117 1
        return $value;
118
    }
119
120 6
    public function generateDatasources(RenderArgumentEmitter $emitter, ConfiguratorData $data): void
121
    {
122 6
        $datasources = $data->getContext()->getDatasources();
123 6
        if (!$datasources) {
124 1
            return;
125
        }
126
127 5
        $data = $datasources->executeAll();
128 5
        foreach ($data as $name => $value) {
129 5
            $argument = new RenderArgument('data', $name, $value);
130 5
            $emitter->emitArgument($argument);
131
        }
132 5
    }
133
134 4
    public function doCreateEditables(RenderArgumentEmitter $emitter, string $name, ConfiguratorData $data): void
135
    {
136 4
        if (!$data->getContext()->getDatasources()) {
137 1
            return;
138
        }
139
140 3
        $editable = $data->getConfig();
141
        if (
142 3
            !isset($editable['datasource'])
143 3
            || !isset($editable['datasource']['name'])
144
        ) {
145 1
            return;
146
        }
147
148 2
        $this->generateDatasources($emitter, $data);
149
150 2
        $datasourceName = $editable['datasource']['name'];
151 2
        $datasourceIdExpression = @$editable['datasource']['id'];
152
153 2
        if (!$emitter->has($datasourceName)) {
154 1
            return;
155
        }
156
157 1
        $dataArgument = $emitter->get($datasourceName);
158
159 1
        unset($editable['datasource']);
160 1
        $items = new ArrayObject();
161
162 1
        foreach ($dataArgument->getValue() as $i => $item) {
163
            //@codeCoverageIgnoreStart
164
            if ($datasourceIdExpression) {
165
                $i = $this
166
                        ->getExpressionWrapper()
167
                        ->evaluateExpression($datasourceIdExpression, ['item' => $item]);
168
            }
169
            //@codeCoverageIgnoreEnd
170
171 1
            $itemArgument = new RenderArgument('editable', $i, $editable);
0 ignored issues
show
Bug introduced by
It seems like $i can also be of type array and array; however, parameter $name of Khusseini\PimcoreRadBric...Argument::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

171
            $itemArgument = new RenderArgument('editable', /** @scrutinizer ignore-type */ $i, $editable);
Loading history...
172 1
            $items[] = $itemArgument;
173
        }
174
175 1
        $argument = new RenderArgument(
176 1
            'collection',
177
            $name,
178
            $items
179
        );
180
181 1
        $emitter->emitArgument($argument);
182 1
    }
183
184 2
    public function supportsEditable(string $editableName, array $config): bool
185
    {
186 2
        return isset($config['datasource']) && isset($config['datasource']['id']);
187
    }
188
189 1
    public function configureEditableOptions(OptionsResolver $optionsResolver): void
190
    {
191 1
        $optionsResolver->setDefault('datasource', []);
192 1
    }
193
194 1
    public function postCreateEditables(string $brickName, ConfiguratorData $data, RenderArgumentEmitter $emitter): void
195
    {
196 1
        $this->generateDatasources($emitter, $data);
197 1
    }
198
199
    /**
200
     * @param array<mixed> $config
201
     *
202
     * @return array<mixed>
203
     * @codeCoverageIgnore
204
     */
205
    protected function resolveBrickconfig(array $config): array
206
    {
207
        $or = new OptionsResolver();
208
        $or->setDefaults(['datasources' => [], 'editables' => []]);
209
        $or->setDefined(array_keys($config));
210
211
        return $or->resolve($config);
212
    }
213
214
    /**
215
     * @param array<mixed> $config
216
     *
217
     * @return array<mixed>
218
     * @codeCoverageIgnore
219
     */
220
    protected function resolveConfig(array $config): array
221
    {
222
        $or = new OptionsResolver();
223
        $or->setDefaults(['datasources' => [], 'areabricks' => []]);
224
        $or->setDefined(array_keys($config));
225
226
        return $or->resolve($config);
227
    }
228
}
229