Completed
Pull Request — master (#1646)
by Karel
04:11
created

Indexable   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 138
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 2

Test Coverage

Coverage 95.56%

Importance

Changes 0
Metric Value
wmc 19
lcom 1
cbo 2
dl 0
loc 138
ccs 43
cts 45
cp 0.9556
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A isObjectIndexable() 0 17 4
A buildCallback() 0 18 5
A buildExpressionCallback() 0 18 3
A getCallback() 0 8 2
A getExpressionLanguage() 0 8 2
A getExpressionVar() 0 10 2
1
<?php
2
3
/*
4
 * This file is part of the FOSElasticaBundle package.
5
 *
6
 * (c) FriendsOfSymfony <http://friendsofsymfony.github.com/>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace FOS\ElasticaBundle\Provider;
13
14
use Symfony\Component\ExpressionLanguage\Expression;
15
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
16
use Symfony\Component\ExpressionLanguage\SyntaxError;
17
18
class Indexable implements IndexableInterface
19
{
20
    /**
21
     * An array of raw configured callbacks for all types.
22
     *
23
     * @var array
24
     */
25
    private $callbacks = [];
26
27
    /**
28
     * An instance of ExpressionLanguage.
29
     *
30
     * @var ExpressionLanguage
31
     */
32
    private $expressionLanguage;
33
34
    /**
35
     * An array of initialised callbacks.
36
     *
37
     * @var array
38
     */
39
    private $initialisedCallbacks = [];
40
41 15
    public function __construct(array $callbacks)
42
    {
43 15
        $this->callbacks = $callbacks;
44 15
    }
45
46
    /**
47
     * Return whether the object is indexable with respect to the callback.
48
     */
49 15
    public function isObjectIndexable(string $indexName, object $object): bool
50
    {
51 15
        if (!$callback = $this->getCallback($indexName, $object)) {
52 1
            return true;
53
        }
54
55 10
        if ($callback instanceof Expression) {
56 6
            return (bool) $this->getExpressionLanguage()->evaluate($callback, [
57 6
                'object' => $object,
58 6
                $this->getExpressionVar($object) => $object,
59
            ]);
60
        }
61
62 5
        return is_string($callback)
63 2
            ? call_user_func([$object, $callback])
64 5
            : call_user_func($callback, $object);
65
    }
66
67
    /**
68
     * Builds and initialises a callback.
69
     *
70
     * @return callable|string|ExpressionLanguage|null
71
     */
72 15
    private function buildCallback(string $index, object $object)
73
    {
74 15
        if (!array_key_exists($index, $this->callbacks)) {
75 1
            return null;
76
        }
77
78 14
        $callback = $this->callbacks[$index];
79
80 14
        if (is_callable($callback) or is_callable([$object, $callback])) {
81 5
            return $callback;
82
        }
83
84 10
        if (is_string($callback)) {
85 8
            return $this->buildExpressionCallback($index, $object, $callback);
86
        }
87
88 2
        throw new \InvalidArgumentException(sprintf('Callback for index "%s" is not a valid callback.', $index));
89
    }
90
91
    /**
92
     * Processes a string expression into an Expression.
93
     */
94 8
    private function buildExpressionCallback(string $index, object $object, string $callback): Expression
95
    {
96 8
        $expression = $this->getExpressionLanguage();
97 8
        if (!$expression) {
98
            throw new \RuntimeException('Unable to process an expression without the ExpressionLanguage component.');
99
        }
100
101
        try {
102 8
            $callback = new Expression($callback);
103 8
            $expression->compile($callback, [
104 8
                'object', $this->getExpressionVar($object),
105
            ]);
106
107 6
            return $callback;
108 2
        } catch (SyntaxError $e) {
109 2
            throw new \InvalidArgumentException(sprintf('Callback for index "%s" is an invalid expression', $index), $e->getCode(), $e);
110
        }
111
    }
112
113
    /**
114
     * Retreives a cached callback, or creates a new callback if one is not found.
115
     *
116
     * @return mixed
117
     */
118 15
    private function getCallback(string $index, object $object)
119
    {
120 15
        if (!array_key_exists($index, $this->initialisedCallbacks)) {
121 15
            $this->initialisedCallbacks[$index] = $this->buildCallback($index, $object);
122
        }
123
124 11
        return $this->initialisedCallbacks[$index];
125
    }
126
127
    /**
128
     * Returns the ExpressionLanguage class if it is available.
129
     */
130 8
    private function getExpressionLanguage(): ?ExpressionLanguage
131
    {
132 8
        if (null === $this->expressionLanguage) {
133 8
            $this->expressionLanguage = new ExpressionLanguage();
134
        }
135
136 8
        return $this->expressionLanguage;
137
    }
138
139
    /**
140
     * Returns the variable name to be used to access the object when using the ExpressionLanguage
141
     * component to parse and evaluate an expression.
142
     *
143
     * @param mixed $object
144
     */
145 8
    private function getExpressionVar($object = null): string
146
    {
147 8
        if (!is_object($object)) {
148
            return 'object';
149
        }
150
151 8
        $ref = new \ReflectionClass($object);
152
153 8
        return strtolower($ref->getShortName());
154
    }
155
}
156