2010-08-09 14:21:59 +01:00
< ? php
/*
2011-01-15 13:29:43 +00:00
* This file is part of the Symfony package .
2010-08-09 14:21:59 +01:00
*
2011-03-06 11:40:06 +00:00
* ( c ) Fabien Potencier < fabien @ symfony . com >
2010-08-09 14:21:59 +01:00
*
2011-01-15 13:29:43 +00:00
* For the full copyright and license information , please view the LICENSE
* file that was distributed with this source code .
2010-08-09 14:21:59 +01:00
*/
2011-01-15 13:29:43 +00:00
namespace Symfony\Component\HttpKernel\Controller ;
2013-01-09 09:41:17 +00:00
use Psr\Log\LoggerInterface ;
2011-01-15 13:29:43 +00:00
use Symfony\Component\HttpFoundation\Request ;
2010-08-09 14:21:59 +01:00
/**
* ControllerResolver .
*
* This implementation uses the '_controller' request attribute to determine
* the controller to execute and uses the request attributes to determine
* the controller method arguments .
*
2011-03-06 11:40:06 +00:00
* @ author Fabien Potencier < fabien @ symfony . com >
2010-08-09 14:21:59 +01:00
*/
2016-03-16 07:56:41 +00:00
class ControllerResolver extends ArgumentResolver implements ControllerResolverInterface
2010-08-09 14:21:59 +01:00
{
2011-03-23 18:47:16 +00:00
private $logger ;
2010-08-09 14:21:59 +01:00
/**
* Constructor .
*
* @ param LoggerInterface $logger A LoggerInterface instance
*/
public function __construct ( LoggerInterface $logger = null )
{
$this -> logger = $logger ;
}
/**
2013-11-20 02:35:05 +00:00
* { @ inheritdoc }
2010-08-09 14:21:59 +01:00
*
* This method looks for a '_controller' request attribute that represents
2011-01-23 11:10:45 +00:00
* the controller name ( a string like ClassName :: MethodName ) .
2010-08-09 14:21:59 +01:00
*/
public function getController ( Request $request )
{
if ( ! $controller = $request -> attributes -> get ( '_controller' )) {
if ( null !== $this -> logger ) {
2015-01-15 09:04:56 +00:00
$this -> logger -> warning ( 'Unable to look for the controller as the "_controller" parameter is missing.' );
2010-08-09 14:21:59 +01:00
}
return false ;
}
2014-03-26 18:20:25 +00:00
if ( is_array ( $controller )) {
2010-09-16 09:46:38 +01:00
return $controller ;
}
2014-03-26 18:20:25 +00:00
if ( is_object ( $controller )) {
if ( method_exists ( $controller , '__invoke' )) {
return $controller ;
}
throw new \InvalidArgumentException ( sprintf ( 'Controller "%s" for URI "%s" is not callable.' , get_class ( $controller ), $request -> getPathInfo ()));
}
2012-02-11 23:34:53 +00:00
if ( false === strpos ( $controller , ':' )) {
if ( method_exists ( $controller , '__invoke' )) {
2014-04-29 16:01:48 +01:00
return $this -> instantiateController ( $controller );
2012-02-11 23:34:53 +00:00
} elseif ( function_exists ( $controller )) {
return $controller ;
}
2011-08-08 22:16:52 +01:00
}
2013-04-20 21:07:10 +01:00
$callable = $this -> createController ( $controller );
2010-08-09 14:21:59 +01:00
2013-04-20 21:07:10 +01:00
if ( ! is_callable ( $callable )) {
2014-04-26 01:10:40 +01:00
throw new \InvalidArgumentException ( sprintf ( 'The controller for URI "%s" is not callable. %s' , $request -> getPathInfo (), $this -> getControllerError ( $callable )));
2010-08-09 14:21:59 +01:00
}
2013-04-20 21:07:10 +01:00
return $callable ;
2010-08-09 14:21:59 +01:00
}
/**
2013-11-20 02:35:05 +00:00
* { @ inheritdoc }
2016-03-16 07:56:41 +00:00
*
* @ deprecated this method is deprecated as of 3.1 and will be removed in 4.0 . Implement the ArgumentResolverInterface or extend the ArgumentResolver instead .
2010-08-09 14:21:59 +01:00
*/
public function getArguments ( Request $request , $controller )
{
2016-03-16 07:56:41 +00:00
@ trigger_error ( sprintf ( '%s is deprecated as of 3.1 and will be removed in 4.0. Implement the %s or extend the %s and inject it in the HttpKernel instead.' , __METHOD__ , ArgumentResolverInterface :: class , ArgumentResolver :: class ), E_USER_DEPRECATED );
2010-08-09 14:21:59 +01:00
2016-03-16 07:56:41 +00:00
return parent :: getArguments ( $request , $controller );
2011-08-08 22:20:53 +01:00
}
2016-03-16 07:56:41 +00:00
/**
* @ deprecated this method is deprecated as of 3.1 and will be removed in 4.0 . Implement the ArgumentResolverInterface or extend the ArgumentResolver instead .
*/
2011-08-08 22:20:53 +01:00
protected function doGetArguments ( Request $request , $controller , array $parameters )
{
2016-03-16 07:56:41 +00:00
@ trigger_error ( sprintf ( '%s is deprecated as of 3.1 and will be removed in 4.0. Implement the %s or extend the %s and inject it in the HttpKernel instead.' , __METHOD__ , ArgumentResolverInterface :: class , ArgumentResolver :: class ), E_USER_DEPRECATED );
2010-08-09 14:21:59 +01:00
2016-03-16 07:56:41 +00:00
return parent :: doGetArguments ( $request , $controller , $parameters );
2010-08-09 14:21:59 +01:00
}
/**
* Returns a callable for the given controller .
*
* @ param string $controller A Controller string
*
2015-10-05 17:52:37 +01:00
* @ return callable A PHP callable
2012-12-16 12:02:54 +00:00
*
* @ throws \InvalidArgumentException
2010-08-09 14:21:59 +01:00
*/
protected function createController ( $controller )
{
if ( false === strpos ( $controller , '::' )) {
throw new \InvalidArgumentException ( sprintf ( 'Unable to find controller "%s".' , $controller ));
}
2011-12-11 20:16:22 +00:00
list ( $class , $method ) = explode ( '::' , $controller , 2 );
2010-08-09 14:21:59 +01:00
if ( ! class_exists ( $class )) {
throw new \InvalidArgumentException ( sprintf ( 'Class "%s" does not exist.' , $class ));
}
2014-04-29 16:01:48 +01:00
return array ( $this -> instantiateController ( $class ), $method );
}
/**
2015-08-24 07:53:33 +01:00
* Returns an instantiated controller .
2014-04-29 16:01:48 +01:00
*
* @ param string $class A class name
*
* @ return object
*/
protected function instantiateController ( $class )
{
return new $class ();
2010-08-09 14:21:59 +01:00
}
2014-04-26 01:10:40 +01:00
private function getControllerError ( $callable )
{
if ( is_string ( $callable )) {
if ( false !== strpos ( $callable , '::' )) {
$callable = explode ( '::' , $callable );
}
if ( class_exists ( $callable ) && ! method_exists ( $callable , '__invoke' )) {
return sprintf ( 'Class "%s" does not have a method "__invoke".' , $callable );
}
if ( ! function_exists ( $callable )) {
return sprintf ( 'Function "%s" does not exist.' , $callable );
}
}
if ( ! is_array ( $callable )) {
return sprintf ( 'Invalid type for controller given, expected string or array, got "%s".' , gettype ( $callable ));
}
if ( 2 !== count ( $callable )) {
return sprintf ( 'Invalid format for controller, expected array(controller, method) or controller::method.' );
}
list ( $controller , $method ) = $callable ;
if ( is_string ( $controller ) && ! class_exists ( $controller )) {
return sprintf ( 'Class "%s" does not exist.' , $controller );
}
$className = is_object ( $controller ) ? get_class ( $controller ) : $controller ;
if ( method_exists ( $controller , $method )) {
return sprintf ( 'Method "%s" on class "%s" should be public and non-abstract.' , $method , $className );
}
$collection = get_class_methods ( $controller );
$alternatives = array ();
foreach ( $collection as $item ) {
$lev = levenshtein ( $method , $item );
if ( $lev <= strlen ( $method ) / 3 || false !== strpos ( $item , $method )) {
$alternatives [] = $item ;
}
}
asort ( $alternatives );
$message = sprintf ( 'Expected method "%s" on class "%s"' , $method , $className );
if ( count ( $alternatives ) > 0 ) {
$message .= sprintf ( ', did you mean "%s"?' , implode ( '", "' , $alternatives ));
} else {
$message .= sprintf ( '. Available methods: "%s".' , implode ( '", "' , $collection ));
}
return $message ;
}
2010-08-09 14:21:59 +01:00
}