Passed
Pull Request — master (#3)
by De Cramer
01:49
created

RuleTransformOperation::getColumnPossibleValues()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 27
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 4

Importance

Changes 0
Metric Value
cc 4
eloc 14
nc 4
nop 4
dl 0
loc 27
rs 9.7998
c 0
b 0
f 0
ccs 7
cts 7
cp 1
crap 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Oliverde8\Component\PhpEtl\ChainOperation\Transformer;
6
7
use oliverde8\AssociativeArraySimplified\AssociativeArray;
8
use Oliverde8\Component\PhpEtl\ChainOperation\AbstractChainOperation;
9
use Oliverde8\Component\PhpEtl\ChainOperation\DataChainOperationInterface;
10
use Oliverde8\Component\PhpEtl\Item\DataItem;
11
use Oliverde8\Component\PhpEtl\Item\DataItemInterface;
12
use Oliverde8\Component\PhpEtl\Item\ItemInterface;
13
use Oliverde8\Component\PhpEtl\Model\ExecutionContext;
14
use Oliverde8\Component\RuleEngine\RuleApplier;
15
16
/**
17
 * Class RuleTransformOperation
18
 *
19
 * @author    de Cramer Oliver<[email protected]>
20
 * @copyright 2018 Oliverde8
21
 * @package Oliverde8\Component\PhpEtl\ChainOperation\Transformer
22
 */
23
class RuleTransformOperation extends AbstractChainOperation implements DataChainOperationInterface
24
{
25
    const VARIABLE_MATCH_REGEX = '/{(?<variables>[^{}]+)}/';
26
27
    /** @var string[] */
28
    protected array $parsedColumns = [];
29
30
    /** @var RuleApplier */
31
    protected RuleApplier $ruleApplier;
32
33
    /** @var array */
34
    protected array $rules;
35
36
    /** @var boolean */
37
    protected bool $add;
38
39
    public function __construct(RuleApplier $ruleApplier, array $rules, bool $add)
40
    {
41
        $this->ruleApplier = $ruleApplier;
42
        $this->rules = $rules;
43 5
        $this->add = $add;
44
    }
45 5
46 5
    public function processData(DataItemInterface $item, ExecutionContext $context): DataItemInterface
47 5
    {
48 5
        $data = $item->getData();
49
        $newData = [];
50
51
        // We add data and don't send new data.
52
        if ($this->add) {
53
            $newData = $data;
54
        }
55
56
        foreach ($this->rules as $column => $rule) {
57
            // Add context to the data.
58 5
            $data['@context'] = array_merge($context->getParameters(), $rule['context'] ?? []);
59
60 5
            $columnsValues = $this->resolveColumnVariables((string) $column, $data, $newData);
61 5
            $possibleColumns = [];
62
            $this->getColumnPossibleValues($column, $columnsValues, [], $possibleColumns);
63
64 5
            foreach ($possibleColumns as $column => $values) {
0 ignored issues
show
Comprehensibility Bug introduced by
$column is overwriting a variable from outer foreach loop.
Loading history...
65 1
                $data['@column'] = $values;
66
                AssociativeArray::setFromKey($newData, $column, $this->ruleApplier->apply($data, $newData, $rule['rules'], []));
67
            }
68 5
        }
69
70 5
        return new DataItem($newData);
71
    }
72 5
73 5
    protected function resolveColumnVariables(string $columnString, array $data, array $newData): array
74 5
    {
75
        $variables = $this->getColumnVariables($columnString);
76 5
        $variableValues = [];
77 5
78 5
        foreach ($variables as $variable) {
79
            $data['@new'] = $newData;
80
            $variableValues[] = ['variable' => $variable,  'value' => AssociativeArray::getFromKey($data, $variable, "")];
81
        }
82 5
83
        return $variableValues;
84
    }
85
86
    protected function getColumnPossibleValues(
87
        string $columnString,
88
        array $variableValues,
89
        array $preparedValues,
90
        array &$valueCombinations
91
    ): void {
92
        if (empty($variableValues)) {
93
            $key = $this->getColumnName($columnString, $preparedValues);
94 5
            $valueCombinations[$key] = $preparedValues;
95
            return;
96 5
        }
97 5
98
        // Shift elements in array.
99 5
        $firsVariable = reset($variableValues);
100 3
        array_shift($variableValues);
101 3
102
        // Handle possible multi values.
103
        if (is_array($firsVariable['value'])) {
104 5
            foreach ($firsVariable['value'] as $value) {
105
                $currentPreparedValues = $preparedValues;
106
                $currentPreparedValues[$firsVariable['variable']] = $value;
107
108
                $this->getColumnPossibleValues($columnString, $variableValues, $currentPreparedValues, $valueCombinations);
109
            }
110
        } else {
111
            $currentPreparedValues[$firsVariable['variable']] = $firsVariable['value'];
0 ignored issues
show
Comprehensibility Best Practice introduced by
$currentPreparedValues was never initialized. Although not strictly required by PHP, it is generally a good practice to add $currentPreparedValues = array(); before regardless.
Loading history...
112
            $this->getColumnPossibleValues($columnString, $variableValues, $currentPreparedValues, $valueCombinations);
113
        }
114
    }
115 5
116
    protected function getColumnName(string $columnString, array $values): string
117 5
    {
118 5
        $variables = [];
119 5
        $varValues = [];
120 5
121
        foreach ($values as $variableName => $value) {
122
            $variables[] = '{' . $variableName . '}';
123
            $varValues[] = $value;
124 3
        }
125 3
126
        return str_replace($variables, $varValues, $columnString);
127
    }
128 3
129 2
    /**
130 2
     * Get variables in a column.
131 2
     */
132
    protected function getColumnVariables(string $columnsString): array
133 2
    {
134
        if (!isset($this->parsedColumns[$columnsString])) {
135
            $matches = [];
136 1
            preg_match_all(self::VARIABLE_MATCH_REGEX, $columnsString, $matches);
137 1
138
            if (isset($matches['variables'])) {
139 3
                $this->parsedColumns[$columnsString] = $matches['variables'];
140
            } else {
141
                $this->parsedColumns[$columnsString] = [];
142
            }
143
        }
144
145
        return $this->parsedColumns[$columnsString];
146
    }
147
}