New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Query param fetcher #185
Query param fetcher #185
Changes from 48 commits
631fe13
8c04a84
192f3ae
bfa891e
e32e078
80d0da4
7cfa318
25517a6
fd1ae02
b03414b
937e273
e7fe284
df59842
ebbfb5c
a52e85d
1cc4ccc
e430694
bf75439
8e19e8f
370e806
e41dd47
8dfb9c4
f81bac8
f39ea93
b784c43
49f68b2
89ece6e
f07bd7a
ed4aaae
a6d434f
e65bb81
ddcc3fa
3dc09ba
9d4c66a
39da182
9cbb25d
0671c11
199f42e
3406ebd
87ccc2b
3535e86
4137c3e
07ae8fe
f6d019d
af142df
37661de
822af06
3e20eac
5c88435
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the FOSRestBundle package. | ||
* | ||
* (c) FriendsOfSymfony <http://friendsofsymfony.github.com/> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace FOS\RestBundle\Controller\Annotations; | ||
|
||
/** | ||
* QueryParam annotation class. | ||
* | ||
* @Annotation | ||
* @author Alexander <iam.asm89@gmail.com> | ||
*/ | ||
class QueryParam | ||
{ | ||
/** @var string */ | ||
public $name; | ||
/** @var string */ | ||
public $requirements; | ||
/** @var string */ | ||
public $default; | ||
/** @var string */ | ||
public $description; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,6 +27,8 @@ | |
*/ | ||
class Configuration implements ConfigurationInterface | ||
{ | ||
private $forceOptionValues = array(false, true, 'force'); | ||
|
||
/** | ||
* Generates the configuration tree. | ||
* | ||
|
@@ -39,6 +41,12 @@ public function getConfigTreeBuilder() | |
|
||
$rootNode | ||
->children() | ||
->scalarNode('query_fetcher_listener')->defaultFalse() | ||
->validate() | ||
->ifNotInArray($this->forceOptionValues) | ||
->thenInvalid('The query_fetcher_listener option does not support %s. Please choose one of '.json_encode($this->forceOptionValues)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. missing one indentation level |
||
->end() | ||
->end() | ||
->arrayNode('routing_loader') | ||
->addDefaultsIfNotSet() | ||
->children() | ||
|
@@ -111,7 +119,12 @@ private function addViewSection(ArrayNodeDefinition $rootNode) | |
->defaultValue(array('html' => true)) | ||
->prototype('boolean')->end() | ||
->end() | ||
->scalarNode('view_response_listener')->defaultValue('force')->end() | ||
->scalarNode('view_response_listener')->defaultValue('force') | ||
->validate() | ||
->ifNotInArray($this->forceOptionValues) | ||
->thenInvalid('The view_response_listener option does not support %s. Please choose one of '.json_encode($this->forceOptionValues)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here |
||
->end() | ||
->end() | ||
->scalarNode('failed_validation')->defaultValue(Codes::HTTP_BAD_REQUEST)->end() | ||
->end() | ||
->end() | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -39,6 +39,7 @@ public function load(array $configs, ContainerBuilder $container) | |
$loader->load('view.xml'); | ||
$loader->load('routing.xml'); | ||
$loader->load('util.xml'); | ||
$loader->load('request.xml'); | ||
|
||
if (version_compare(FOSRestBundle::getSymfonyVersion(Kernel::VERSION), '2.1.0', '<')) { | ||
$container->setParameter('fos_rest.routing.loader.controller.class', $container->getParameter('fos_rest.routing.loader_2_0.controller.class')); | ||
|
@@ -128,6 +129,14 @@ public function load(array $configs, ContainerBuilder $container) | |
} else { | ||
$container->setParameter($this->getAlias().'.mime_types', array()); | ||
} | ||
|
||
if (!empty($config['query_fetcher_listener'])) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. you could use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this would mean i need to write a lot more code into the tests .. its fine like it is. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. well, my comment is not really accurate anymore as it is not a boolean anymore (because of |
||
$loader->load('query_fetcher_listener.xml'); | ||
|
||
if ('force' === $config['query_fetcher_listener']) { | ||
$container->setParameter($this->getAlias().'.query_fetch_listener.set_params_as_attributes', true); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the FOSRestBundle package. | ||
* | ||
* (c) FriendsOfSymfony <http://friendsofsymfony.github.com/> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace FOS\RestBundle\EventListener; | ||
|
||
use Symfony\Component\HttpKernel\Event\FilterControllerEvent, | ||
Symfony\Component\HttpKernel\HttpKernelInterface, | ||
Symfony\Component\DependencyInjection\ContainerInterface; | ||
|
||
/** | ||
* This listener handles various setup tasks related to the query fetcher | ||
* | ||
* Setting the controller callable on the query fetcher | ||
* Setting the query fetcher as a request attribute | ||
* | ||
* @author Lukas Kahwe Smith <smith@pooteeweet.org> | ||
*/ | ||
class QueryFetcherListener | ||
{ | ||
/** | ||
* @var ContainerInterface | ||
*/ | ||
private $container; | ||
|
||
private $setParamsAsAttributes; | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* @param ContainerInterface $container container | ||
*/ | ||
public function __construct(ContainerInterface $container, $setParamsAsAttributes = false) | ||
{ | ||
$this->container = $container; | ||
$this->setParamsAsAttributes = $setParamsAsAttributes; | ||
} | ||
|
||
/** | ||
* Core controller handler | ||
* | ||
* @param FilterControllerEvent $event The event | ||
*/ | ||
public function onKernelController(FilterControllerEvent $event) | ||
{ | ||
$request = $event->getRequest(); | ||
$queryFetcher = $this->container->get('fos_rest.request.query_fetcher'); | ||
|
||
$queryFetcher->setController($event->getController()); | ||
$request->attributes->set('queryFetcher', $queryFetcher); | ||
|
||
if ($this->setParamsAsAttributes) { | ||
$params = $queryFetcher->all(); | ||
foreach ($params as $name => $param) { | ||
if ($request->attributes->has($name)) { | ||
$msg = sprintf("QueryFetcher parameter conflicts with a path parameter '$name' for route '%s'", $request->attributes->get('_route')); | ||
throw new \InvalidArgumentException($msg); | ||
} | ||
|
||
$request->attributes->set($name, $param); | ||
} | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,135 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the FOSRestBundle package. | ||
* | ||
* (c) FriendsOfSymfony <http://friendsofsymfony.github.com/> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace FOS\RestBundle\Request; | ||
|
||
use Symfony\Component\HttpFoundation\Request; | ||
|
||
/** | ||
* Helper to validate query parameters from the active request. | ||
* | ||
* @author Alexander <iam.asm89@gmail.com> | ||
* @author Lukas Kahwe Smith <smith@pooteeweet.org> | ||
*/ | ||
class QueryFetcher implements QueryFetcherInterface | ||
{ | ||
/** | ||
* @var QueryParamReader | ||
*/ | ||
private $queryParamReader; | ||
|
||
/** | ||
* @var Request | ||
*/ | ||
private $request; | ||
|
||
/** | ||
* @var array | ||
*/ | ||
private $params; | ||
|
||
/** | ||
* @var callable | ||
*/ | ||
private $controller; | ||
|
||
/** | ||
* Initializes fetcher. | ||
* | ||
* @param QueryParamReader $queryParamReader Query param reader | ||
* @param Request $request Active request | ||
*/ | ||
public function __construct(QueryParamReader $queryParamReader, Request $request) | ||
{ | ||
$this->queryParamReader = $queryParamReader; | ||
$this->request = $request; | ||
} | ||
|
||
/** | ||
* @abstract | ||
* @param callable $controller | ||
* | ||
* @return void | ||
*/ | ||
public function setController($controller) | ||
{ | ||
$this->controller = $controller; | ||
} | ||
|
||
/** | ||
* Get a validated query parameter. | ||
* | ||
* @param string $name Name of the query parameter | ||
* @param Boolean $strict If a requirement mismatch should cause an exception | ||
* | ||
* @return mixed Value of the parameter. | ||
*/ | ||
public function get($name, $strict = false) | ||
{ | ||
if (null === $this->params) { | ||
$this->initParams(); | ||
} | ||
|
||
if (!array_key_exists($name, $this->params)) { | ||
throw new \InvalidArgumentException(sprintf("No @QueryParam configuration for parameter '%s'.", $name)); | ||
} | ||
|
||
$config = $this->params[$name]; | ||
$default = $config->default; | ||
$param = $this->request->query->get($name, $default); | ||
|
||
// Set default if the requirements do not match | ||
if ($param !== $default && !preg_match('#^'.$config->requirements.'$#xs', $param)) { | ||
if ($strict) { | ||
throw new \RuntimeException("Query parameter value '$param', does not match requirements '{$config->requirements}'"); | ||
} | ||
|
||
$param = $default; | ||
} | ||
|
||
return $param; | ||
} | ||
|
||
/** | ||
* Get all validated query parameter. | ||
* | ||
* @param Boolean $strict If a requirement mismatch should cause an exception | ||
* | ||
* @return array Values of all the parameters. | ||
*/ | ||
public function all($strict = false) | ||
{ | ||
$params = array(); | ||
foreach ($this->params as $name => $config) { | ||
$params[$name] = $this->get($name, $strict); | ||
} | ||
|
||
return $params; | ||
} | ||
|
||
/** | ||
* Initialize the parameters | ||
* | ||
* @throws \InvalidArgumentException | ||
*/ | ||
private function initParams() | ||
{ | ||
if (empty($this->controller)) { | ||
throw new \InvalidArgumentException('Controller and method needs to be set via setController'); | ||
} | ||
|
||
if (!is_array($this->controller) || empty($this->controller[0]) || !is_object($this->controller[0])) { | ||
throw new \InvalidArgumentException('Controller needs to be set as a class instance (closures/functions are not supported)'); | ||
} | ||
|
||
$this->params = $this->queryParamReader->read(new \ReflectionClass($this->controller[0]), $this->controller[1]); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
<?php | ||
|
||
/* | ||
* This file is part of the FOSRestBundle package. | ||
* | ||
* (c) FriendsOfSymfony <http://friendsofsymfony.github.com/> | ||
* | ||
* For the full copyright and license information, please view the LICENSE | ||
* file that was distributed with this source code. | ||
*/ | ||
|
||
namespace FOS\RestBundle\Request; | ||
|
||
use Symfony\Component\HttpFoundation\Request; | ||
|
||
/** | ||
* Helper interface to validate query parameters from the active request. | ||
* | ||
* @author Alexander <iam.asm89@gmail.com> | ||
* @author Lukas Kahwe Smith <smith@pooteeweet.org> | ||
*/ | ||
interface QueryFetcherInterface | ||
{ | ||
/** | ||
* @abstract | ||
* @param callable $controller | ||
* | ||
* @return void | ||
*/ | ||
function setController($controller); | ||
|
||
/** | ||
* Get a validated query parameter. | ||
* | ||
* @param string $name Name of the query parameter | ||
* @param Boolean $strict If a requirement mismatch should cause an exception | ||
* | ||
* @return mixed Value of the parameter. | ||
*/ | ||
function get($name, $strict = false); | ||
|
||
/** | ||
* Get all validated query parameter. | ||
* | ||
* @param Boolean $strict If a requirement mismatch should cause an exception | ||
* | ||
* @return array Values of all the parameters. | ||
*/ | ||
function all($strict = false); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you should probably add the annotations allowing the AnnotationReader to validate annotations as of Common 2.2 (see the ORM or @schmittjoh's bundles for instance)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed.