Completed
Push — master ( 35bf32...5024d1 )
by Karel
12s
created

Indexable::getExpressionLanguage()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 8
ccs 4
cts 4
cp 1
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 0
crap 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
     * @param string $indexName
50
     * @param string $typeName
51
     * @param mixed  $object
52
     *
53
     * @return bool
54
     */
55 15
    public function isObjectIndexable($indexName, $typeName, $object)
56
    {
57 15
        $type = sprintf('%s/%s', $indexName, $typeName);
58 15
        $callback = $this->getCallback($type, $object);
59 11
        if (!$callback) {
60 1
            return true;
61
        }
62
63 10
        if ($callback instanceof Expression) {
64 6
            return (bool) $this->getExpressionLanguage()->evaluate($callback, [
65 6
                'object' => $object,
66 6
                $this->getExpressionVar($object) => $object,
67
            ]);
68
        }
69
70 5
        return is_string($callback)
71 2
            ? call_user_func([$object, $callback])
72 5
            : call_user_func($callback, $object);
73
    }
74
75
    /**
76
     * Builds and initialises a callback.
77
     *
78
     * @param string $type
79
     * @param object $object
80
     *
81
     * @return callable|string|ExpressionLanguage|null
82
     */
83 15
    private function buildCallback($type, $object)
84
    {
85 15
        if (!array_key_exists($type, $this->callbacks)) {
86 1
            return null;
87
        }
88
89 14
        $callback = $this->callbacks[$type];
90
91 14
        if (is_callable($callback) or is_callable([$object, $callback])) {
92 5
            return $callback;
93
        }
94
95 10
        if (is_string($callback)) {
96 8
            return $this->buildExpressionCallback($type, $object, $callback);
97
        }
98
99 2
        throw new \InvalidArgumentException(sprintf('Callback for type "%s" is not a valid callback.', $type));
100
    }
101
102
    /**
103
     * Processes a string expression into an Expression.
104
     *
105
     * @param string $type
106
     * @param mixed  $object
107
     * @param string $callback
108
     *
109
     * @return Expression
110
     */
111 8
    private function buildExpressionCallback($type, $object, $callback)
112
    {
113 8
        $expression = $this->getExpressionLanguage();
114 8
        if (!$expression) {
115
            throw new \RuntimeException('Unable to process an expression without the ExpressionLanguage component.');
116
        }
117
118
        try {
119 8
            $callback = new Expression($callback);
120 8
            $expression->compile($callback, [
121 8
                'object', $this->getExpressionVar($object),
122
            ]);
123
124 6
            return $callback;
125 2
        } catch (SyntaxError $e) {
126 2
            throw new \InvalidArgumentException(sprintf(
127 2
                'Callback for type "%s" is an invalid expression',
128
                $type
129 2
            ), $e->getCode(), $e);
130
        }
131
    }
132
133
    /**
134
     * Retreives a cached callback, or creates a new callback if one is not found.
135
     *
136
     * @param string $type
137
     * @param object $object
138
     *
139
     * @return mixed
140
     */
141 15
    private function getCallback($type, $object)
142
    {
143 15
        if (!array_key_exists($type, $this->initialisedCallbacks)) {
144 15
            $this->initialisedCallbacks[$type] = $this->buildCallback($type, $object);
145
        }
146
147 11
        return $this->initialisedCallbacks[$type];
148
    }
149
150
    /**
151
     * Returns the ExpressionLanguage class if it is available.
152
     *
153
     * @return ExpressionLanguage|null
154
     */
155 8
    private function getExpressionLanguage()
156
    {
157 8
        if (null === $this->expressionLanguage) {
158 8
            $this->expressionLanguage = new ExpressionLanguage();
159
        }
160
161 8
        return $this->expressionLanguage;
162
    }
163
164
    /**
165
     * Returns the variable name to be used to access the object when using the ExpressionLanguage
166
     * component to parse and evaluate an expression.
167
     *
168
     * @param mixed $object
169
     *
170
     * @return string
171
     */
172 8
    private function getExpressionVar($object = null)
173
    {
174 8
        if (!is_object($object)) {
175
            return 'object';
176
        }
177
178 8
        $ref = new \ReflectionClass($object);
179
180 8
        return strtolower($ref->getShortName());
181
    }
182
}
183