Completed
Push — master ( 2b8e94...32de88 )
by Jean
11:58
created

InRule::setOperands()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
nc 1
nop 1
dl 0
loc 5
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * InRule
4
 *
5
 * @package php-logical-filter
6
 * @author  Jean Claveau
7
 */
8
namespace JClaveau\LogicalFilter\Rule;
9
10
/**
11
 * This class represents a rule that expect a value to belong to a list of others.
12
 */
13
class InRule extends OrRule
14
{
15
    /** @var string operator */
16
    const operator = 'in';
17
18
    /** @var string $field */
19
    protected $field;
20
21
    /** @var array $native_possibilities */
22
    protected $native_possibilities = [];
23
24
    /** @var array $cache */
25
    protected $cache = [
26
        'array'       => null,
27
        'string'      => null,
28
        'semantic_id' => null,
29
    ];
30
31
    /**
32
     * @param string $field         The field to apply the rule on.
33
     * @param mixed  $possibilities The values the field can belong to.
34
     */
35
    public function __construct( $field, $possibilities, array $options=[] )
36
    {
37
        if (!empty($options)) {
38
            $this->setOptions($options);
39
        }
40
41
        $this->field = $field;
42
        $this->addPossibilities( $possibilities );
43
    }
44
45
    /**
46
     * @return string The field
47
     */
48
    public function getField()
49
    {
50
        return $this->field;
51
    }
52
53
    /**
54
     * @return $this
55
     */
56
    public function setField($field)
57
    {
58
        if ($this->field != $field) {
59
            $this->field = $field;
60
            $this->flushCache();
61
        }
62
63
        return $this;
64
    }
65
66
    /**
67
     * @param  array|callable Associative array of renamings or callable
0 ignored issues
show
Bug introduced by
The type JClaveau\LogicalFilter\Rule\Associative was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
68
     *                        that would rename the fields.
69
     *
70
     * @return AbstractAtomicRule $this
71
     */
72
    public final function renameFields($renamings)
73
    {
74
        $old_field = $this->field;
75
76
        if (is_callable($renamings)) {
77
            $this->field = call_user_func($renamings, $this->field);
78
        }
79
        elseif (is_array($renamings)) {
80
            if (isset($renamings[$this->field]))
81
                $this->field = $renamings[$this->field];
82
        }
83
        else {
84
            throw new \InvalidArgumentException(
85
                "\$renamings MUST be a callable or an associative array "
86
                ."instead of: " . var_export($renamings, true)
87
            );
88
        }
89
90
        if ($old_field != $this->field)
91
            $this->flushCache();
92
93
        return $this;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this returns the type JClaveau\LogicalFilter\Rule\InRule which is incompatible with the documented return type JClaveau\LogicalFilter\Rule\AbstractAtomicRule.
Loading history...
94
    }
95
96
    /**
97
     * @return array
98
     */
99
    public function getPossibilities()
100
    {
101
        return array_values( $this->native_possibilities );
102
    }
103
104
    /**
105
     * @param  mixed possibilities
0 ignored issues
show
Bug introduced by
The type JClaveau\LogicalFilter\Rule\possibilities was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
106
     *
107
     * @return InRule $this
108
     */
109
    public function addPossibilities($possibilities)
110
    {
111
        if (    is_object($possibilities)
112
            &&  $possibilities instanceof \IteratorAggregate
113
            &&  method_exists($possibilities, 'toArray')
114
        ) {
115
            $possibilities = $possibilities->toArray();
116
        }
117
118
        if (!is_array($possibilities))
119
            $possibilities = [$possibilities];
120
121
        $possibilities = array_map([$this, 'checkOperandAndExtractValue'], $possibilities);
122
123
        // unique possibilities
124
        foreach ($possibilities as &$possibility) {
125
126
            if (is_scalar($possibility))
127
                $id = hash('crc32b', $possibility);
128
            else
129
                $id = hash('crc32b', serialize($possibility));
130
131
            if (!isset($this->native_possibilities[ $id ])) {
132
                $this->native_possibilities[ $id ] = $possibility;
133
                $require_cache_flush = true;
134
            }
135
        }
136
137
        if (isset($require_cache_flush))
138
            $this->flushCache();
139
140
        return $this;
141
    }
142
143
    /**
144
     * @param  array possibilities
145
     *
146
     * @return InRule $this
147
     */
148
    public function addOperand( AbstractRule $operand )
149
    {
150
        $this->addPossibilities([$operand->getValue()]);
0 ignored issues
show
Bug introduced by
The method getValue() does not exist on JClaveau\LogicalFilter\Rule\AbstractRule. It seems like you code against a sub-type of JClaveau\LogicalFilter\Rule\AbstractRule such as JClaveau\LogicalFilter\Rule\NotEqualRule or JClaveau\LogicalFilter\Rule\EqualRule. ( Ignorable by Annotation )

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

150
        $this->addPossibilities([$operand->/** @scrutinizer ignore-call */ getValue()]);
Loading history...
151
152
        return $this;
153
    }
154
155
    /**
156
     * @param  mixed possibilities
157
     *
158
     * @return InRule $this
159
     */
160
    public function setPossibilities($possibilities)
161
    {
162
        $this->native_possibilities = [];
163
        $this->addPossibilities($possibilities);
164
        $this->flushCache();
165
166
        return $this;
167
    }
168
169
    /**
170
     * @param  array possibilities
171
     *
172
     * @return InRule $this
173
     */
174
    public function setOperands(array $operands)
175
    {
176
        $this->addPossibilities($operands);
177
178
        return $this;
179
    }
180
181
    /**
182
     *
183
     */
184
    protected function checkOperandAndExtractValue($operand)
185
    {
186
        if (! $operand instanceof AbstractAtomicRule)
187
            return $operand;
188
189
        if ( ! ($operand instanceof EqualRule && $operand->getField() == $this->field) ) {
190
            throw new \InvalidArgumentException(
191
                "Trying to set an invalid operand of an InRule: "
192
                .var_export($operand, true)
193
            );
194
        }
195
196
        return $operand->getValue();
197
    }
198
199
    /**
200
     * @return InRule $this
201
     */
202
    public function getOperands()
203
    {
204
        if (!empty($this->cache['operands'])) {
205
            return $this->cache['operands'];
206
        }
207
208
        $operands = [];
209
        foreach ($this->native_possibilities as $value)
210
            $operands[] = new EqualRule($this->field, $value);
211
212
        return $this->cache['operands'] = $operands;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->cache['operands'] = $operands returns the type JClaveau\LogicalFilter\Rule\EqualRule[]|array which is incompatible with the documented return type JClaveau\LogicalFilter\Rule\InRule.
Loading history...
213
    }
214
215
    /**
216
     * @return array
217
     */
218
    public function getValues()
219
    {
220
        return $this->getPossibilities();
221
    }
222
223
    /**
224
     * @param array $options   + show_instance=false Display the operator of the rule or its instance id
225
     *
226
     * @return array
227
     */
228
    public function toArray(array $options=[])
229
    {
230
        $default_options = [
231
            'show_instance' => false,
232
        ];
233
        foreach ($default_options as $default_option => &$default_value) {
234
            if (!isset($options[ $default_option ]))
235
                $options[ $default_option ] = $default_value;
236
        }
237
238
        $class = get_class($this);
239
240
        if (!$options['show_instance'] && isset($this->cache['array']))
241
            return $this->cache['array'];
242
243
        $array = [
244
            $this->getField(),
245
            $options['show_instance'] ? $this->getInstanceId() : $class::operator,
246
            $this->getValues(),
247
        ];
248
249
        if (!$options['show_instance'])
250
            return $this->cache['array'] = $array;
251
        else
252
            return $array;
253
    }
254
255
    /**
256
     */
257
    public function toString(array $options=[])
258
    {
259
        if (isset($this->cache['string']))
260
            return $this->cache['string'];
261
262
        $operator = self::operator;
263
264
        $stringified_possibilities = '[' . implode(', ', array_map(function($possibility) {
265
            return var_export($possibility, true);
266
        }, $this->getPossibilities()) ) .']';
267
268
        return $this->cache['string'] = "['{$this->getField()}', '$operator', $stringified_possibilities]";
269
    }
270
271
    /**
272
     */
273
    public function isNormalizationAllowed(array $contextual_options)
274
    {
275
        if (($threshold = $this->getOption('in.normalization_threshold', $contextual_options)) === null) {
276
            return false;
277
        }
278
279
        return count($this->native_possibilities) <= $threshold;
280
    }
281
282
    /**
283
     * @return bool If the InRule can have a solution or not
284
     */
285
    public function hasSolution(array $contextual_options=[])
286
    {
287
        return !empty($this->getPossibilities());
288
    }
289
290
    /**
291
     * There is no negations into an InRule
292
     */
293
    public function removeNegations(array $contextual_options)
294
    {
295
        return $this;
296
    }
297
298
    /**/
299
}
300