Skip to content

Instantly share code, notes, and snippets.

@tystr
Last active December 17, 2015 13:19
Show Gist options
  • Select an option

  • Save tystr/5616563 to your computer and use it in GitHub Desktop.

Select an option

Save tystr/5616563 to your computer and use it in GitHub Desktop.
<?php
namespace MyNamespace\Controller;
use JMS\DiExtraBundle\Annotation\Inject;
class PostsController
{
/**
* @Inject("my_namespace.post_repository")
* @var \MyNamespace\Repository\PostRepository
*/
protected $repository;
/**
* @Put("/posts/{id}")
*
* @param Request $request
* @param Post $post
* @param string $id
* @param ValidationErrors $errors
*
* @return Post|ValidationErrors
*/
public function putPostAction(Request $request, Post $post, $id, ValidationErrors $errors = null)
{
if (null !== $errors) {
return $errors;
}
$this->repository->replacePost($id, $post);
return $post;
}
}
<?php
namespace MyNamespace\Request\ParamConverter;
use Doctrine\Common\Persistence\Mapping\MappingException;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\Validator\ValidatorInterface;
use Symfony\Component\HttpFoundation\Request;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface;
use Sensio\Bundle\FrameworkExtraBundle\Request\ParamConverter\ParamConverterInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Doctrine\Common\Persistence\ObjectRepository;
use JMS\Serializer\SerializerInterface;
use JMS\Serializer\Naming\PropertyNamingStrategyInterface;
use Metadata\Driver\AdvancedDriverInterface;
use MyNamespace\Model\ValidationErrors;
class RequestBodyParamConverter implements ParamConverterInterface
{
/**
* @var SerializerInterface
*/
protected $serializer;
/**
* @var ValidatorInterface
*/
protected $validator;
/**
* @var ObjectManager
*/
protected $om;
/**
* @var AdvancedDriverInterface
*/
protected $metadataDriver;
/**
* @var PropertyNamingStrategyInterface
*/
protected $namingStrategy;
/**
* @var ObjectRepository
*/
protected $repository;
/**
* @param SerializerInterface $serializer
* @param ValidatorInterface $validator
* @param ObjectManager $om
* @param AdvancedDriverInterface $metadataDriver
* @param PropertyNamingStrategyInterface $namingStrategy
*/
public function __construct(
SerializerInterface $serializer,
ValidatorInterface $validator,
ObjectManager $om,
AdvancedDriverInterface $metadataDriver,
PropertyNamingStrategyInterface $namingStrategy
) {
$this->serializer = $serializer;
$this->validator = $validator;
$this->om = $om;
$this->metadataDriver = $metadataDriver;
$this->namingStrategy = $namingStrategy;
}
/**
* {@inheritDoc}
*/
public function apply(Request $request, ConfigurationInterface $configuration)
{
$name = $configuration->getName();
$class = $configuration->getClass();
if (null === $name || 'MyNamespace\Model\ValidationErrors' === $class) {
return false;
}
$object = $this->serializer->deserialize(
$request->getContent(),
$configuration->getClass(),
$request->getRequestFormat()
);
if ($request->getMethod() == 'PUT' || $request->getMethod() == 'PATCH') {
$id = $request->attributes->get('_route_params[id]', null, true);
if (null === $id || null === $this->repository->find($id)) {
throw new NotFoundHttpException();
}
}
$errors = new ValidationErrors($this->validator->validate($object));
// Add errors for extra fields
$translatedNames = [];
$metadata = $this->metadataDriver->loadMetadataForClass(new \ReflectionClass($class));
foreach ($metadata->propertyMetadata as $propertyMetadata) {
$translatedNames[] = $this->namingStrategy->translateName($propertyMetadata);
}
foreach ($request->request->all() as $key => $value) {
if (!in_array($key, $translatedNames)) {
$errors->addError($key, 'Invalid field name.');
}
}
if (count($errors->getErrors()) > 0) {
$request->attributes->set('errors', $errors);
}
$request->attributes->set($name, $object);
return true;
}
/**
* {@inheritDoc}
*/
public function supports(ConfigurationInterface $configuration)
{
try {
return $this->repository = $this->om->getRepository($configuration->getClass());
} catch (MappingException $e) {
return false;
}
}
}
<?php
namespace MyNamespace\Model\ValidationErrors;
use Symfony\Component\Validator\ConstraintViolationListInterface;
class ValidationErrors
{
/**
* @var int
*/
protected $statusCode = 400;
/**
* @var array
*/
protected $errors = [];
/**
* @param ConstraintViolationListInterface $constraintViolationList
*/
public function __construct(ConstraintViolationListInterface $constraintViolationList)
{
foreach ($constraintViolationList as $violation) {
$this->errors[][$violation->getPropertyPath()] = $violation->getMessage();
}
}
/**
* @return array
*/
public function getErrors()
{
return $this->errors;
}
/**
* @param string $property
* @param string $message
*/
public function addError($property, $message)
{
$this->errors[][$property] = $message;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment