Initial commit

This commit is contained in:
2020-10-07 10:37:15 +02:00
commit ce5f440392
28157 changed files with 4429172 additions and 0 deletions

View File

@@ -0,0 +1,59 @@
<?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;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadataFactoryInterface;
use Symfony\Component\HttpKernel\Event\FilterControllerArgumentsEvent;
/**
* @author Ryan Weaver <ryan@knpuniversity.com>
*/
class ArgumentNameConverter
{
private $argumentMetadataFactory;
public function __construct(ArgumentMetadataFactoryInterface $argumentMetadataFactory)
{
$this->argumentMetadataFactory = $argumentMetadataFactory;
}
/**
* Returns an associative array of the controller arguments for the event.
*
* @param FilterControllerArgumentsEvent $event
*
* @return array
*/
public function getControllerArguments(FilterControllerArgumentsEvent $event)
{
$namedArguments = $event->getRequest()->attributes->all();
$argumentMetadatas = $this->argumentMetadataFactory->createArgumentMetadata($event->getController());
$controllerArguments = $event->getArguments();
foreach ($argumentMetadatas as $index => $argumentMetadata) {
if ($argumentMetadata->isVariadic()) {
// set the rest of the arguments as this arg's value
$namedArguments[$argumentMetadata->getName()] = \array_slice($controllerArguments, $index);
break;
}
if (!array_key_exists($index, $controllerArguments)) {
throw new \LogicException(sprintf('Could not find an argument value for argument %d of the controller.', $index));
}
$namedArguments[$argumentMetadata->getName()] = $controllerArguments[$index];
}
return $namedArguments;
}
}

View File

@@ -0,0 +1,54 @@
<?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\ArgumentValueResolver;
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface;
use Symfony\Component\HttpKernel\ControllerMetadata\ArgumentMetadata;
/**
* Injects the RequestInterface, MessageInterface or ServerRequestInterface when requested.
*
* @author Iltar van der Berg <kjarli@gmail.com>
*/
final class Psr7ServerRequestResolver implements ArgumentValueResolverInterface
{
private static $supportedTypes = [
'Psr\Http\Message\ServerRequestInterface' => true,
'Psr\Http\Message\RequestInterface' => true,
'Psr\Http\Message\MessageInterface' => true,
];
private $httpMessageFactory;
public function __construct(HttpMessageFactoryInterface $httpMessageFactory)
{
$this->httpMessageFactory = $httpMessageFactory;
}
/**
* {@inheritdoc}
*/
public function supports(Request $request, ArgumentMetadata $argument)
{
return isset(self::$supportedTypes[$argument->getType()]);
}
/**
* {@inheritdoc}
*/
public function resolve(Request $request, ArgumentMetadata $argument)
{
yield $this->httpMessageFactory->createRequest($request);
}
}

View File

@@ -0,0 +1,84 @@
<?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;
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()) {
$request->attributes->set($param, null);
return true;
}
$class = $configuration->getClass();
if (isset($options['format'])) {
$date = $class::createFromFormat($options['format'], $value);
if (0 < DateTime::getLastErrors()['warning_count']) {
$date = false;
}
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 $class($value);
}
$request->attributes->set($param, $date);
return true;
}
/**
* {@inheritdoc}
*/
public function supports(ParamConverter $configuration)
{
if (null === $configuration->getClass()) {
return false;
}
return 'DateTime' === $configuration->getClass() || is_subclass_of($configuration->getClass(), \PHP_VERSION_ID < 50500 ? 'DateTime' : 'DateTimeInterface');
}
}

View File

@@ -0,0 +1,344 @@
<?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 Doctrine\DBAL\Types\ConversionException;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Symfony\Component\ExpressionLanguage\ExpressionLanguage;
use Symfony\Component\ExpressionLanguage\SyntaxError;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpFoundation\Request;
use Doctrine\Common\Persistence\ManagerRegistry;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\NoResultException;
/**
* DoctrineParamConverter.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class DoctrineParamConverter implements ParamConverterInterface
{
/**
* @var ManagerRegistry
*/
private $registry;
/**
* @var ExpressionLanguage
*/
private $language;
/**
* @var array
*/
private $defaultOptions;
public function __construct(ManagerRegistry $registry = null, ExpressionLanguage $expressionLanguage = null, array $options = [])
{
$this->registry = $registry;
$this->language = $expressionLanguage;
$defaultValues = [
'entity_manager' => null,
'exclude' => [],
'mapping' => [],
'strip_null' => false,
'expr' => null,
'id' => null,
'repository_method' => null,
'map_method_signature' => false,
'evict_cache' => false,
];
$this->defaultOptions = array_merge($defaultValues, $options);
}
/**
* {@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);
}
$errorMessage = null;
if ($expr = $options['expr']) {
$object = $this->findViaExpression($class, $request, $expr, $options, $configuration);
if (null === $object) {
$errorMessage = sprintf('The expression "%s" returned null', $expr);
}
// find by identifier?
} elseif (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()) {
$message = sprintf('%s object not found by the @%s annotation.', $class, $this->getAnnotationName($configuration));
if ($errorMessage) {
$message .= ' '.$errorMessage;
}
throw new NotFoundHttpException($message);
}
$request->attributes->set($name, $object);
return true;
}
private 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 ($options['repository_method']) {
$method = $options['repository_method'];
} else {
$method = 'find';
}
$om = $this->getManager($options['entity_manager'], $class);
if ($options['evict_cache'] && $om instanceof EntityManagerInterface) {
$cacheProvider = $om->getCache();
if ($cacheProvider && $cacheProvider->containsEntity($class, $id)) {
$cacheProvider->evictEntity($class, $id);
}
}
try {
return $om->getRepository($class)->$method($id);
} catch (NoResultException $e) {
return;
} catch (ConversionException $e) {
return;
}
}
private function getIdentifier(Request $request, $options, $name)
{
if (null !== $options['id']) {
if (!\is_array($options['id'])) {
$name = $options['id'];
} elseif (\is_array($options['id'])) {
$id = [];
foreach ($options['id'] as $field) {
if (false !== strstr($field, '%s')) {
// Convert "%s_uuid" to "foobar_uuid"
$field = sprintf($field, $name);
}
$id[$field] = $request->attributes->get($field);
}
return $id;
}
}
if ($request->attributes->has($name)) {
return $request->attributes->get($name);
}
if ($request->attributes->has('id') && !$options['id']) {
return $request->attributes->get('id');
}
return false;
}
private function findOneBy($class, Request $request, $options)
{
if (!$options['mapping']) {
$keys = $request->attributes->keys();
$options['mapping'] = $keys ? array_combine($keys, $keys) : [];
}
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 ($options['id'] && null === $request->attributes->get($options['id'])) {
return false;
}
$criteria = [];
$em = $this->getManager($options['entity_manager'], $class);
$metadata = $em->getClassMetadata($class);
$mapMethodSignature = $options['repository_method']
&& $options['map_method_signature']
&& true === $options['map_method_signature'];
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 null !== $value;
});
}
if (!$criteria) {
return false;
}
if ($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;
} catch (ConversionException $e) {
return;
}
}
private function findDataByMapMethodSignature($em, $class, $repositoryMethod, $criteria)
{
$arguments = [];
$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);
}
private function findViaExpression($class, Request $request, $expression, $options, ParamConverter $configuration)
{
if (null === $this->language) {
throw new \LogicException(sprintf('To use the @%s tag with the "expr" option, you need to install the ExpressionLanguage component.', $this->getAnnotationName($configuration)));
}
$repository = $this->getManager($options['entity_manager'], $class)->getRepository($class);
$variables = array_merge($request->attributes->all(), ['repository' => $repository]);
try {
return $this->language->evaluate($expression, $variables);
} catch (NoResultException $e) {
return;
} catch (ConversionException $e) {
return;
} catch (SyntaxError $e) {
throw new \LogicException(sprintf('Error parsing expression -- %s -- (%s)', $expression, $e->getMessage()), 0, $e);
}
}
/**
* {@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->getManagerNames())) {
return false;
}
if (null === $configuration->getClass()) {
return false;
}
$options = $this->getOptions($configuration, false);
// Doctrine Entity?
$em = $this->getManager($options['entity_manager'], $configuration->getClass());
if (null === $em) {
return false;
}
return !$em->getMetadataFactory()->isTransient($configuration->getClass());
}
private function getOptions(ParamConverter $configuration, $strict = true)
{
$passedOptions = $configuration->getOptions();
if (isset($passedOptions['repository_method'])) {
@trigger_error('The repository_method option of @ParamConverter is deprecated and will be removed in 6.0. Use the expr option or @Entity.', E_USER_DEPRECATED);
}
if (isset($passedOptions['map_method_signature'])) {
@trigger_error('The map_method_signature option of @ParamConverter is deprecated and will be removed in 6.0. Use the expr option or @Entity.', E_USER_DEPRECATED);
}
$extraKeys = array_diff(array_keys($passedOptions), array_keys($this->defaultOptions));
if ($extraKeys && $strict) {
throw new \InvalidArgumentException(sprintf('Invalid option(s) passed to @%s: %s', $this->getAnnotationName($configuration), implode(', ', $extraKeys)));
}
return array_replace($this->defaultOptions, $passedOptions);
}
private function getManager($name, $class)
{
if (null === $name) {
return $this->registry->getManagerForClass($class);
}
return $this->registry->getManager($name);
}
private function getAnnotationName(ParamConverter $configuration)
{
$r = new \ReflectionClass($configuration);
return $r->getShortName();
}
}

View File

@@ -0,0 +1,40 @@
<?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 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.
*
* @return bool True if the object is supported, else false
*/
public function supports(ParamConverter $configuration);
}

View File

@@ -0,0 +1,141 @@
<?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;
/**
* Managers converters.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Henrik Bjornskov <henrik@bjrnskov.dk>
*/
class ParamConverterManager
{
/**
* @var array
*/
private $converters = [];
/**
* @var array
*/
private $namedConverters = [];
/**
* 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 array|object $configurations
*/
public function apply(Request $request, $configurations)
{
if (\is_object($configurations)) {
$configurations = [$configurations];
}
foreach ($configurations as $configuration) {
$this->applyConverter($request, $configuration);
}
}
/**
* Applies converter on request based on the given configuration.
*/
private function applyConverter(Request $request, ParamConverter $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 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 (null !== $priority) {
if (!isset($this->converters[$priority])) {
$this->converters[$priority] = [];
}
$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 = [];
foreach ($this->converters as $all) {
$converters = array_merge($converters, $all);
}
return $converters;
}
}