Update
This commit is contained in:
parent
a37785b391
commit
33458b2ca3
9915 changed files with 1247019 additions and 0 deletions
|
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony framework.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* This source file is subject to the MIT license that is bundled
|
||||
* with this source code in the file LICENSE.
|
||||
*/
|
||||
|
||||
namespace Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use DateTime;
|
||||
|
||||
/**
|
||||
* Convert DateTime instances from request attribute variable.
|
||||
*
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
*/
|
||||
class DateTimeParamConverter implements ParamConverterInterface
|
||||
{
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @throws NotFoundHttpException When invalid date given
|
||||
*/
|
||||
public function apply(Request $request, ParamConverter $configuration)
|
||||
{
|
||||
$param = $configuration->getName();
|
||||
|
||||
if (!$request->attributes->has($param)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$options = $configuration->getOptions();
|
||||
$value = $request->attributes->get($param);
|
||||
|
||||
if (!$value && $configuration->isOptional()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($options['format'])) {
|
||||
$date = DateTime::createFromFormat($options['format'], $value);
|
||||
|
||||
if (!$date) {
|
||||
throw new NotFoundHttpException(sprintf('Invalid date given for parameter "%s".', $param));
|
||||
}
|
||||
} else {
|
||||
if (false === strtotime($value)) {
|
||||
throw new NotFoundHttpException(sprintf('Invalid date given for parameter "%s".', $param));
|
||||
}
|
||||
|
||||
$date = new DateTime($value);
|
||||
}
|
||||
|
||||
$request->attributes->set($param, $date);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(ParamConverter $configuration)
|
||||
{
|
||||
if (null === $configuration->getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return 'DateTime' === $configuration->getClass();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,248 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Doctrine\Common\Persistence\ManagerRegistry;
|
||||
use Doctrine\ORM\NoResultException;
|
||||
|
||||
/**
|
||||
* DoctrineParamConverter.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
class DoctrineParamConverter implements ParamConverterInterface
|
||||
{
|
||||
/**
|
||||
* @var ManagerRegistry
|
||||
*/
|
||||
protected $registry;
|
||||
|
||||
public function __construct(ManagerRegistry $registry = null)
|
||||
{
|
||||
$this->registry = $registry;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*
|
||||
* @throws \LogicException When unable to guess how to get a Doctrine instance from the request information
|
||||
* @throws NotFoundHttpException When object not found
|
||||
*/
|
||||
public function apply(Request $request, ParamConverter $configuration)
|
||||
{
|
||||
$name = $configuration->getName();
|
||||
$class = $configuration->getClass();
|
||||
$options = $this->getOptions($configuration);
|
||||
|
||||
if (null === $request->attributes->get($name, false)) {
|
||||
$configuration->setIsOptional(true);
|
||||
}
|
||||
|
||||
// find by identifier?
|
||||
if (false === $object = $this->find($class, $request, $options, $name)) {
|
||||
// find by criteria
|
||||
if (false === $object = $this->findOneBy($class, $request, $options)) {
|
||||
if ($configuration->isOptional()) {
|
||||
$object = null;
|
||||
} else {
|
||||
throw new \LogicException(sprintf('Unable to guess how to get a Doctrine instance from the request information for parameter "%s".', $name));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (null === $object && false === $configuration->isOptional()) {
|
||||
throw new NotFoundHttpException(sprintf('%s object not found.', $class));
|
||||
}
|
||||
|
||||
$request->attributes->set($name, $object);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function find($class, Request $request, $options, $name)
|
||||
{
|
||||
if ($options['mapping'] || $options['exclude']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$id = $this->getIdentifier($request, $options, $name);
|
||||
|
||||
if (false === $id || null === $id) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($options['repository_method'])) {
|
||||
$method = $options['repository_method'];
|
||||
} else {
|
||||
$method = 'find';
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->getManager($options['entity_manager'], $class)->getRepository($class)->$method($id);
|
||||
} catch (NoResultException $e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
protected function getIdentifier(Request $request, $options, $name)
|
||||
{
|
||||
if (isset($options['id'])) {
|
||||
if (!is_array($options['id'])) {
|
||||
$name = $options['id'];
|
||||
} elseif (is_array($options['id'])) {
|
||||
$id = array();
|
||||
foreach ($options['id'] as $field) {
|
||||
$id[$field] = $request->attributes->get($field);
|
||||
}
|
||||
|
||||
return $id;
|
||||
}
|
||||
}
|
||||
|
||||
if ($request->attributes->has($name)) {
|
||||
return $request->attributes->get($name);
|
||||
}
|
||||
|
||||
if ($request->attributes->has('id') && !isset($options['id'])) {
|
||||
return $request->attributes->get('id');
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function findOneBy($class, Request $request, $options)
|
||||
{
|
||||
if (!$options['mapping']) {
|
||||
$keys = $request->attributes->keys();
|
||||
$options['mapping'] = $keys ? array_combine($keys, $keys) : array();
|
||||
}
|
||||
|
||||
foreach ($options['exclude'] as $exclude) {
|
||||
unset($options['mapping'][$exclude]);
|
||||
}
|
||||
|
||||
if (!$options['mapping']) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if a specific id has been defined in the options and there is no corresponding attribute
|
||||
// return false in order to avoid a fallback to the id which might be of another object
|
||||
if (isset($options['id']) && null === $request->attributes->get($options['id'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$criteria = array();
|
||||
$em = $this->getManager($options['entity_manager'], $class);
|
||||
$metadata = $em->getClassMetadata($class);
|
||||
|
||||
$mapMethodSignature = isset($options['repository_method'])
|
||||
&& isset($options['map_method_signature'])
|
||||
&& $options['map_method_signature'] === true;
|
||||
|
||||
foreach ($options['mapping'] as $attribute => $field) {
|
||||
if ($metadata->hasField($field)
|
||||
|| ($metadata->hasAssociation($field) && $metadata->isSingleValuedAssociation($field))
|
||||
|| $mapMethodSignature) {
|
||||
$criteria[$field] = $request->attributes->get($attribute);
|
||||
}
|
||||
}
|
||||
|
||||
if ($options['strip_null']) {
|
||||
$criteria = array_filter($criteria, function ($value) { return !is_null($value); });
|
||||
}
|
||||
|
||||
if (!$criteria) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (isset($options['repository_method'])) {
|
||||
$repositoryMethod = $options['repository_method'];
|
||||
} else {
|
||||
$repositoryMethod = 'findOneBy';
|
||||
}
|
||||
|
||||
try {
|
||||
if ($mapMethodSignature) {
|
||||
return $this->findDataByMapMethodSignature($em, $class, $repositoryMethod, $criteria);
|
||||
}
|
||||
|
||||
return $em->getRepository($class)->$repositoryMethod($criteria);
|
||||
} catch (NoResultException $e) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private function findDataByMapMethodSignature($em, $class, $repositoryMethod, $criteria)
|
||||
{
|
||||
$arguments = array();
|
||||
$repository = $em->getRepository($class);
|
||||
$ref = new \ReflectionMethod($repository, $repositoryMethod);
|
||||
foreach ($ref->getParameters() as $parameter) {
|
||||
if (array_key_exists($parameter->name, $criteria)) {
|
||||
$arguments[] = $criteria[$parameter->name];
|
||||
} elseif ($parameter->isDefaultValueAvailable()) {
|
||||
$arguments[] = $parameter->getDefaultValue();
|
||||
} else {
|
||||
throw new \InvalidArgumentException(sprintf('Repository method "%s::%s" requires that you provide a value for the "$%s" argument.', get_class($repository), $repositoryMethod, $parameter->name));
|
||||
}
|
||||
}
|
||||
|
||||
return $ref->invokeArgs($repository, $arguments);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(ParamConverter $configuration)
|
||||
{
|
||||
// if there is no manager, this means that only Doctrine DBAL is configured
|
||||
if (null === $this->registry || !count($this->registry->getManagers())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (null === $configuration->getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$options = $this->getOptions($configuration);
|
||||
|
||||
// Doctrine Entity?
|
||||
$em = $this->getManager($options['entity_manager'], $configuration->getClass());
|
||||
if (null === $em) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !$em->getMetadataFactory()->isTransient($configuration->getClass());
|
||||
}
|
||||
|
||||
protected function getOptions(ParamConverter $configuration)
|
||||
{
|
||||
return array_replace(array(
|
||||
'entity_manager' => null,
|
||||
'exclude' => array(),
|
||||
'mapping' => array(),
|
||||
'strip_null' => false,
|
||||
), $configuration->getOptions());
|
||||
}
|
||||
|
||||
private function getManager($name, $class)
|
||||
{
|
||||
if (null === $name) {
|
||||
return $this->registry->getManagerForClass($class);
|
||||
}
|
||||
|
||||
return $this->registry->getManager($name);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Converts request parameters to objects and stores them as request
|
||||
* attributes, so they can be injected as controller method arguments.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
*/
|
||||
interface ParamConverterInterface
|
||||
{
|
||||
/**
|
||||
* Stores the object in the request.
|
||||
*
|
||||
* @param Request $request The request
|
||||
* @param ParamConverter $configuration Contains the name, class and options of the object
|
||||
*
|
||||
* @return bool True if the object has been successfully set, else false
|
||||
*/
|
||||
public function apply(Request $request, ParamConverter $configuration);
|
||||
|
||||
/**
|
||||
* Checks if the object is supported.
|
||||
*
|
||||
* @param ParamConverter $configuration Should be an instance of ParamConverter
|
||||
*
|
||||
* @return bool True if the object is supported, else false
|
||||
*/
|
||||
public function supports(ParamConverter $configuration);
|
||||
}
|
||||
|
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter;
|
||||
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface;
|
||||
|
||||
/**
|
||||
* Managers converters.
|
||||
*
|
||||
* @author Fabien Potencier <fabien@symfony.com>
|
||||
* @author Henrik Bjornskov <henrik@bjrnskov.dk>
|
||||
*/
|
||||
class ParamConverterManager
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $converters = array();
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $namedConverters = array();
|
||||
|
||||
/**
|
||||
* Applies all converters to the passed configurations and stops when a
|
||||
* converter is applied it will move on to the next configuration and so on.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param array|object $configurations
|
||||
*/
|
||||
public function apply(Request $request, $configurations)
|
||||
{
|
||||
if (is_object($configurations)) {
|
||||
$configurations = array($configurations);
|
||||
}
|
||||
|
||||
foreach ($configurations as $configuration) {
|
||||
$this->applyConverter($request, $configuration);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply converter on request based on the given configuration.
|
||||
*
|
||||
* @param Request $request
|
||||
* @param ConfigurationInterface $configuration
|
||||
*/
|
||||
protected function applyConverter(Request $request, ConfigurationInterface $configuration)
|
||||
{
|
||||
$value = $request->attributes->get($configuration->getName());
|
||||
$className = $configuration->getClass();
|
||||
|
||||
// If the value is already an instance of the class we are trying to convert it into
|
||||
// we should continue as no conversion is required
|
||||
if (is_object($value) && $value instanceof $className) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($converterName = $configuration->getConverter()) {
|
||||
if (!isset($this->namedConverters[$converterName])) {
|
||||
throw new \RuntimeException(sprintf(
|
||||
"No converter named '%s' found for conversion of parameter '%s'.",
|
||||
$converterName, $configuration->getName()
|
||||
));
|
||||
}
|
||||
|
||||
$converter = $this->namedConverters[$converterName];
|
||||
|
||||
if (!$converter->supports($configuration)) {
|
||||
throw new \RuntimeException(sprintf(
|
||||
"Converter '%s' does not support conversion of parameter '%s'.",
|
||||
$converterName, $configuration->getName()
|
||||
));
|
||||
}
|
||||
|
||||
$converter->apply($request, $configuration);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ($this->all() as $converter) {
|
||||
if ($converter->supports($configuration)) {
|
||||
if ($converter->apply($request, $configuration)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a parameter converter.
|
||||
*
|
||||
* Converters match either explicitly via $name or by iteration over all
|
||||
* converters with a $priority. If you pass a $priority = null then the
|
||||
* added converter will not be part of the iteration chain and can only
|
||||
* be invoked explicitly.
|
||||
*
|
||||
* @param ParamConverterInterface $converter A ParamConverterInterface instance
|
||||
* @param int $priority The priority (between -10 and 10).
|
||||
* @param string $name Name of the converter.
|
||||
*/
|
||||
public function add(ParamConverterInterface $converter, $priority = 0, $name = null)
|
||||
{
|
||||
if ($priority !== null) {
|
||||
if (!isset($this->converters[$priority])) {
|
||||
$this->converters[$priority] = array();
|
||||
}
|
||||
|
||||
$this->converters[$priority][] = $converter;
|
||||
}
|
||||
|
||||
if (null !== $name) {
|
||||
$this->namedConverters[$name] = $converter;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all registered param converters.
|
||||
*
|
||||
* @return array An array of param converters
|
||||
*/
|
||||
public function all()
|
||||
{
|
||||
krsort($this->converters);
|
||||
|
||||
$converters = array();
|
||||
foreach ($this->converters as $all) {
|
||||
$converters = array_merge($converters, $all);
|
||||
}
|
||||
|
||||
return $converters;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Symfony package.
|
||||
*
|
||||
* (c) Fabien Potencier <fabien@symfony.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter;
|
||||
|
||||
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
|
||||
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
|
||||
use Symfony\Component\HttpFoundation\Request;
|
||||
|
||||
/**
|
||||
* Converts HttpFoundation Request to PSR-7 ServerRequest using the bridge.
|
||||
*
|
||||
* @author Kévin Dunglas <dunglas@gmail.com>
|
||||
*/
|
||||
class PsrServerRequestParamConverter implements ParamConverterInterface
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $supportedTypes = array(
|
||||
'Psr\Http\Message\ServerRequestInterface' => true,
|
||||
'Psr\Http\Message\RequestInterface' => true,
|
||||
'Psr\Http\Message\MessageInterface' => true,
|
||||
);
|
||||
/**
|
||||
* @var HttpMessageFactoryInterface
|
||||
*/
|
||||
private $httpMessageFactory;
|
||||
|
||||
public function __construct(HttpMessageFactoryInterface $httpMessageFactory)
|
||||
{
|
||||
$this->httpMessageFactory = $httpMessageFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function apply(Request $request, ParamConverter $configuration)
|
||||
{
|
||||
$request->attributes->set($configuration->getName(), $this->httpMessageFactory->createRequest($request));
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function supports(ParamConverter $configuration)
|
||||
{
|
||||
if (null === $configuration->getClass()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return isset(self::$supportedTypes[$configuration->getClass()]);
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue