Passed
Push — master ( d6ce84...9c42e9 )
by Gaetano
10:07
created

NonScalarReferenceSetterTrait::getSelfName()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 7
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
nc 1
nop 0
dl 0
loc 7
rs 10
c 1
b 0
f 0
1
<?php
2
3
namespace Kaliop\eZMigrationBundle\Core\Executor;
4
5
use Kaliop\eZMigrationBundle\API\Collection\AbstractCollection;
6
use Kaliop\eZMigrationBundle\API\Value\MigrationStep;
7
8
/**
9
 * A trait used by Executors which allow to set non-scalar values to references.
10
 * ATM besides scalars we support arrays and collections as reference values
11
 */
12
trait NonScalarReferenceSetterTrait
13
{
14
    // traits can not have constants...
15
16
    static $RESULT_TYPE_SINGLE = 1;
17
    static $RESULT_TYPE_MULTIPLE = 2;
18
    static $RESULT_TYPE_ANY = 3;
19
20
    static $EXPECT_ONE = 'one';
21
    static $EXPECT_ANY = 'any';
22
    static $EXPECT_MANY = 'many';
23
24
    protected function validateResultsCount($results, $step)
25
    {
26
        // q: what if we get a scalar result but we expect an array/collection ?
27
        if (is_array($results) || $results instanceof AbstractCollection) {
28
            if (count($results) > 1 && !$this->allowMultipleResults($step)) {
29
                throw new \InvalidArgumentException($this->getSelfName() . ' found multiple matching ' . $this->getResultsName($results) . 's but expects one');
30
            }
31
            if (count($results) == 0 && !$this->allowEmptyResults($step)) {
32
                throw new \InvalidArgumentException($this->getSelfName() . ' found no matching' . $this->getResultsName($results) . 's but expects at least one');
33
            }
34
        }
35
    }
36
37
    /**
38
     * @param $step
39
     * @return bool
40
     */
41
    protected function allowEmptyResults($step)
42
    {
43
        if (isset($step->dsl['expect'])) {
44
            return ($step->dsl['expect'] == self::$EXPECT_ANY);
45
        }
46
47
        // BC
48
        if (isset($step->dsl['references_type'])) {
49
            switch($step->dsl['references_type']) {
50
                case 'array':
51
                    return (isset($step->dsl['references_allow_empty']) && $step->dsl['references_allow_empty'] == true);
52
                case 'scalar':
53
                    return false;
54
                default:
55
                    throw new \InvalidArgumentException('Unexpected value for references_type element: ' . $step->dsl['references_type']);
56
            }
57
        }
58
59
        // if there are references to set, except the always_scalar ones, then we want a single result
60
        if (isset($step->dsl['references']) && $this->hasNonScalarReferences($step->dsl['references'])) {
61
            return false;
62
        }
63
64
        return true;
65
    }
66
67
    protected function allowMultipleResults($step)
68
    {
69
        return in_array($this->getResultsType($step), array(self::$RESULT_TYPE_MULTIPLE, self::$RESULT_TYPE_ANY));
70
    }
71
72
    /**
73
     * @param $step
74
     * @return int
75
     */
76
    protected function getResultsType($step)
77
    {
78
        if (isset($step->dsl['expect'])) {
79
            return ($step->dsl['expect'] == self::$EXPECT_ONE) ? self::$RESULT_TYPE_SINGLE : self::$RESULT_TYPE_MULTIPLE;
80
        }
81
82
        // BC
83
        if (isset($step->dsl['references_type'])) {
84
            switch($step->dsl['references_type']) {
85
                case 'array':
86
                    return self::$RESULT_TYPE_MULTIPLE;
87
                case 'scalar':
88
                    return self::$RESULT_TYPE_SINGLE;
89
                default:
90
                    throw new \InvalidArgumentException('Unexpected value for references_type element: ' . $step->dsl['references_type']);
91
            }
92
        }
93
94
        // if there are references to set, except the always_scalar ones, then we want a single result
95
        if (isset($step->dsl['references']) && $this->hasNonScalarReferences($step->dsl['references'])) {
96
            return self::$RESULT_TYPE_SINGLE;
97
        }
98
99
        return self::$RESULT_TYPE_ANY;
100
    }
101
102
    /**
103
     * @param array $referencesDefinition
104
     * @return bool
105
     */
106
    protected function hasNonScalarReferences($referencesDefinition)
107
    {
108
        foreach($referencesDefinition as $referenceDefinition) {
109
            if (!$this->isScalarReference($referenceDefinition))
110
            {
111
                return true;
112
            }
113
        }
114
115
        return false;
116
    }
117
118
    /**
119
     * @param array $referenceDefinition
120
     * @return bool
121
     */
122
    protected abstract function isScalarReference($referenceDefinition);
123
124
    /**
125
     * Verifies compatibility between the definition of the references to be set and the data set to extract them from.
126
     * NB: for multivalued/array refs, we assume that the users by default expect at least one value.
127
     * NB: for scalar results we do not validate anything, as they are always valid (we do not coerce them to arrays)
128
     * @param AbstractCollection|array|mixed $results
129
     * @param array $referencesDefinition
130
     * @param MigrationStep $step
131
     * @return void throws when incompatibility is found
132
     * @todo we should encapsulate the whole info about refs to be set in a single data structure, instead of poking inside $step...
133
     * @deprecated
134
     */
135
    /*protected function insureResultsCountCompatibility($results, $referencesDefinition, $step)
136
    {
137
        if (!$this->hasNonScalarReferences($referencesDefinition)) {
138
            return;
139
        }
140
141
        if (is_array($results) || $results instanceof AbstractCollection) {
142
            if (count($results) > 1 && !$this->allowMultipleResults($step)) {
143
                throw new \InvalidArgumentException($this->getSelfName() . ' does not support setting references for multiple ' . $this->getResultsName($results) . 's');
144
            }
145
            if (count($results) == 0 && !$this->allowEmptyResults($step)) {
146
                throw new \InvalidArgumentException($this->getSelfName() . ' does not support setting references for no ' . $this->getResultsName($results) . 's');
147
            }
148
        }
149
    }*/
150
151
    /**
152
     * @return string
153
     */
154
    protected function getSelfName()
155
    {
156
        $className = get_class($this);
157
        $array = explode('\\', $className);
158
        $className = end($array);
159
        // CamelCase to Camel Case using negative look-behind in regexp
160
        return preg_replace('/(?<!^)[A-Z]/', ' $0', $className);
161
    }
162
163
    /**
164
     * @param $collection
165
     * @return string
166
     */
167
    protected function getResultsName($collection)
168
    {
169
        if (is_array($collection)) {
170
            return 'result';
171
        }
172
173
        $className = get_class($collection);
174
        $array = explode('\\', $className);
175
        $className = str_replace('Collection', '', end($array));
176
        // CamelCase to snake case using negative look-behind in regexp
177
        return strtolower(preg_replace('/(?<!^)[A-Z]/', ' $0', $className));
178
    }
179
}
180