@@ -55,6 +55,7 @@ class Indexable implements IndexableInterface
5555
5656 /**
5757 * @param array $callbacks
58+ * @param ContainerInterface $container
5859 */
5960 public function __construct (array $ callbacks , ContainerInterface $ container )
6061 {
@@ -112,37 +113,46 @@ private function buildCallback($type, $object)
112113 return $ callback ;
113114 }
114115
115- if (is_array ($ callback )) {
116- list ($ class , $ method ) = $ callback + array (null , null );
117-
118- if (is_object ($ class )) {
119- $ class = get_class ($ class );
120- }
116+ if (is_array ($ callback ) && !is_object ($ callback [0 ])) {
117+ return $ this ->processArrayToCallback ($ type , $ callback );
118+ }
121119
122- if (strpos ($ class , '@ ' ) === 0 ) {
123- $ service = $ this ->container ->get (substr ($ class , 1 ));
120+ if (is_string ($ callback )) {
121+ return $ this ->buildExpressionCallback ($ type , $ object , $ callback );
122+ }
124123
125- return array ( $ service , $ method );
126- }
124+ throw new \ InvalidArgumentException ( sprintf ( ' Callback for type "%s" is not a valid callback. ' , $ type ) );
125+ }
127126
128- if ($ class && $ method ) {
129- throw new \InvalidArgumentException (sprintf ('Callback for type "%s", "%s::%s()", is not callable. ' , $ type , $ class , $ method ));
130- }
127+ /**
128+ * Processes a string expression into an Expression.
129+ *
130+ * @param string $type
131+ * @param mixed $object
132+ * @param string $callback
133+ *
134+ * @return Expression
135+ */
136+ private function buildExpressionCallback ($ type , $ object , $ callback )
137+ {
138+ $ expression = $ this ->getExpressionLanguage ();
139+ if (!$ expression ) {
140+ throw new \RuntimeException ('Unable to process an expression without the ExpressionLanguage component. ' );
131141 }
132142
133- if ( is_string ( $ callback ) && $ expression = $ this -> getExpressionLanguage ()) {
143+ try {
134144 $ callback = new Expression ($ callback );
145+ $ expression ->compile ($ callback , array (
146+ 'object ' , $ this ->getExpressionVar ($ object )
147+ ));
135148
136- try {
137- $ expression ->compile ($ callback , array ('object ' , $ this ->getExpressionVar ($ object )));
138-
139- return $ callback ;
140- } catch (SyntaxError $ e ) {
141- throw new \InvalidArgumentException (sprintf ('Callback for type "%s" is an invalid expression ' , $ type ), $ e ->getCode (), $ e );
142- }
149+ return $ callback ;
150+ } catch (SyntaxError $ e ) {
151+ throw new \InvalidArgumentException (sprintf (
152+ 'Callback for type "%s" is an invalid expression ' ,
153+ $ type
154+ ), $ e ->getCode (), $ e );
143155 }
144-
145- throw new \InvalidArgumentException (sprintf ('Callback for type "%s" is not a valid callback. ' , $ type ));
146156 }
147157
148158 /**
@@ -163,30 +173,68 @@ private function getCallback($type, $object)
163173 }
164174
165175 /**
166- * @return bool|ExpressionLanguage
176+ * Returns the ExpressionLanguage class if it is available.
177+ *
178+ * @return ExpressionLanguage|null
167179 */
168180 private function getExpressionLanguage ()
169181 {
170- if (null === $ this ->expressionLanguage ) {
171- if (!class_exists ('Symfony\Component\ExpressionLanguage\ExpressionLanguage ' )) {
172- return false ;
173- }
174-
182+ if (null === $ this ->expressionLanguage && class_exists ('Symfony\Component\ExpressionLanguage\ExpressionLanguage ' )) {
175183 $ this ->expressionLanguage = new ExpressionLanguage ();
176184 }
177185
178186 return $ this ->expressionLanguage ;
179187 }
180188
181189 /**
190+ * Returns the variable name to be used to access the object when using the ExpressionLanguage
191+ * component to parse and evaluate an expression.
192+ *
182193 * @param mixed $object
183194 *
184195 * @return string
185196 */
186197 private function getExpressionVar ($ object = null )
187198 {
199+ if (!is_object ($ object )) {
200+ return 'object ' ;
201+ }
202+
188203 $ ref = new \ReflectionClass ($ object );
189204
190205 return strtolower ($ ref ->getShortName ());
191206 }
207+
208+ /**
209+ * Processes an array into a callback. Replaces the first element with a service if
210+ * it begins with an @.
211+ *
212+ * @param string $type
213+ * @param array $callback
214+ * @return array
215+ */
216+ private function processArrayToCallback ($ type , array $ callback )
217+ {
218+ list ($ class , $ method ) = $ callback + array (null , '__invoke ' );
219+
220+ if (strpos ($ class , '@ ' ) === 0 ) {
221+ $ service = $ this ->container ->get (substr ($ class , 1 ));
222+ $ callback = array ($ service , $ method );
223+
224+ if (!is_callable ($ callback )) {
225+ throw new \InvalidArgumentException (sprintf (
226+ 'Method "%s" on service "%s" is not callable. ' ,
227+ $ method ,
228+ substr ($ class , 1 )
229+ ));
230+ }
231+
232+ return $ callback ;
233+ }
234+
235+ throw new \InvalidArgumentException (sprintf (
236+ 'Unable to parse callback array for type "%s" ' ,
237+ $ type
238+ ));
239+ }
192240}
0 commit comments