Symfony API Entity Validation - validation

I have a class with annotations for the validation.
namespace AppBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
use JMS\Serializer\Annotation as Serialize;
use Symfony\Component\Validator\Constraints as Assert;
use AppBundle\Annotation\Link;
/**
* #Serialize\ExclusionPolicy("all")
* #Serialize\AccessType(type="public_method")
* #Serialize\AccessorOrder("custom", custom = {"id", "name", "awardType", "nominations"})
* #ORM\Entity(repositoryClass="AppBundle\Repository\AwardRepository")
* #ORM\Table(name="awards")
* #Link("self", route = "api_awards_show", params = { "id": "object.getId()" })
*/
class Award extends Entity
{
/**
* #Serialize\Expose()
* #Serialize\Type(name="string")
* #Assert\Type(type="string")
* #Assert\NotBlank(message="Please enter a name for the Award")
* #Assert\Length(min="3", max="255")
* #ORM\Column(type="string")
*/
private $name;
/**
* #Serialize\Expose()
* #Serialize\Type(name="AppBundle\Entity\AwardType")
* #Serialize\MaxDepth(depth=2)
* #Assert\Valid()
* #ORM\ManyToOne(
* targetEntity="AppBundle\Entity\AwardType",
* inversedBy="awards"
* )
*/
private $awardType;
/**
* #Serialize\Expose()
* #Serialize\Type(name="ArrayCollection<AppBundle\Entity\Nomination>")
* #Serialize\MaxDepth(depth=2)
* #ORM\OneToMany(
* targetEntity="AppBundle\Entity\Nomination",
* mappedBy="award"
* )
*/
private $nominations;
}
I then validate that entity with the following:
$validator = $this->get('validator');
$errors = $validator->validate($entity);
if (count($errors) > 0) {
$apiProblem = new ApiProblem(
400,
ApiProblem::TYPE_VALIDATION_ERROR
);
$apiProblem->set('errors', ['testing', 'array']);
throw new ApiProblemException($apiProblem);
}
$this->save($entity);
This works fine the problem is that i cant get the information on which fields have errors and their error message. $errors in this case seems to be of an unknown type which i cant seem to get the error messages for any fields.
How do i get the error messages of that object?

You can get the exact messages of the errors like this:
$errors = $validator->validate($entity);
if (count($errors) > 0) {
$formattedErrors = [];
foreach ($errors as $error) {
$formattedErrors[$error->getPropertyPath()] = [
'message' => sprintf('The property "%s" with value "%s" violated a requirement (%s)', $error->getPropertyPath(), $error->getInvalidValue(), $error->getMessage());
];
}
return new \Symfony\Component\HttpFoundation\JsonResponse($formattedErrors, 400);
}
For example, that could output:
[
'field1' => 'The property "field1" with value "" violated a requirement (Cannot be null)',
// ...
]

Related

How to automatically filter embedding relations data?

I have 2 simple entity related between themselves:
<?php
declare(strict_types=1);
namespace App\Entity;
// use ... ;
/**
* #ApiResource(
* subresourceOperations={
* // ...
* },
* // ... ,
* normalizationContext={"groups" = {"category:read"}}
* )
* # ...
*/
class Category
{
// ...
/**
* #ORM\OneToMany(targetEntity="Object", mappedBy="category")
* #ApiSubresource
* #Groups({"category:read"})
*/
private $objects;
// ...
public function getObjects(): Collection
{
return $this->objects;
}
}
And
<?php
declare(strict_types=1);
namespace App\Entity;
// use ... ;
/**
* #ApiResource(
* // ...
* )
* # ...
*/
class Object
{
// ...
/**
* #ORM\ManyToOne(targetEntity="App\Entity\Category")
* #ORM\JoinColumn(nullable=false)
* #Groups({"object:read", "object:write"})
*/
private $category;
/**
* #ORM\Column(type="boolean")
*/
private $isActive = true;
/**
* #ORM\Column(type="string", length=255, nullable=true)
* #Groups({"object:read", "object:write", "category:read"})
*/
private $name;
// ...
}
I want to get by /api/сategories/{id} related data Objects, where isActive = true. Now I get all the records.
I tried to use QueryItemExtensionInterface andQueryCollectionExtensionInterface, but I still get all the records. fetch ="EAGER" also didn't help me
I clarify, I do not want to get this by subresource /api/categories/{id}/objects. I want to get it using /api/сategories/{id}
I also want this to depend on the role of the user. So that the admin can get all the records and the user only isActive = true
Any ideas how to do this?
Use the Boolean Filter with categories?objects.isActive=1. This filter must be set up on the relation property as described here.

TYPO3 9, assign form validation errors to the corresponding field

Normally TYPO3 assigns a variable in FrontEnd with the name validationResults and it looks like that.
Then we have to iterate through the Error objects and get a list with all the errors and their messages. But there is no way to take each one individually and assign it on the corresponding field where the error appears.
So the question is, how do i do it?
Best regards,
After some programming and a help from larry-pete (typo3.slack.com) i found a solution.
I created my own ViewHelper and it looks like this:
ext_localconf.php
$GLOBALS['TYPO3_CONF_VARS']['SYS']['fluid']['namespaces']['mytag'][] = 'Vendor\\ExtensionName\\ViewHelpers';
Classes/ViewHelpers/Form/ErrorViewHelper.php
namespace Vendor\ExtensionName\ViewHelpers\Form;
use TYPO3\CMS\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3\CMS\Fluid\ViewHelpers\Form\AbstractFormFieldViewHelper;
class ErrorViewHelper extends AbstractFormFieldViewHelper
{
use CompileWithRenderStatic;
/**
* As this ViewHelper renders HTML, the output must not be escaped.
*
* #var bool
*/
protected $escapeOutput = false;
public function initializeArguments()
{
$this->registerArgument('for', 'string', 'The name of the error name (e.g. argument name or property name). This can also be a property path (like blog.title), and will then only display the validation errors of that property.', false, '');
$this->registerArgument('as', 'string', '', false, 'flattenedErrors');
}
/**
* #param array $arguments
* #param \Closure $renderChildrenClosure
* #param RenderingContextInterface $renderingContext
* #return mixed
*/
public static function renderStatic(array $arguments, \Closure $renderChildrenClosure, RenderingContextInterface $renderingContext)
{
$as = $arguments['as'];
$for = $arguments['for'];
$templateVariableContainer = $renderingContext->getVariableProvider();
$controllerContext = $renderingContext->getcontrollerContext();
$validationResults = $controllerContext->getRequest()->getOriginalRequestMappingResults();
if ($validationResults !== null){
$validationResults = $validationResults->forProperty($for);
}
$flattenedErrors = $validationResults->getErrors();
$output = $renderChildrenClosure();
$withKeys = [];
if (empty($output)) {
if ($flattenedErrors) {
foreach ($flattenedErrors as $error) {
$withKeys[$error->getTitle()] = $error;
}
}
}
$templateVariableContainer->add($as, $withKeys);
return $output;
}
}
Form.html
<mytag:form.error as="error" for="error"/>
And this returns:
So now, you can do something like that:
<f:if condition="{offer.firstName}"><span style="display: block">{offer.firstName.message}</span></f:if>
Best regards
I changed your Viewhelper a bit because it didn't worked in my version (typo3 9)
<?php
namespace Vendor\Extension\ViewHelpers;
use TYPO3Fluid\Fluid\Core\Rendering\RenderingContextInterface;
use TYPO3Fluid\Fluid\Core\ViewHelper\Traits\CompileWithRenderStatic;
use TYPO3Fluid\Fluid\Core\ViewHelper\AbstractViewHelper;
class ErrorViewHelper extends AbstractViewHelper
{
use CompileWithRenderStatic;
/**
* As this ViewHelper renders HTML, the output must not be escaped.
*
* #var bool
*/
protected $escapeOutput = false;
public function initializeArguments()
{
$this->registerArgument('for', 'string', 'The name of the error name (e.g. argument name or property name). This can also be a property path (like blog.title), and will then only display the validation errors of that property.', false, '');
}
/**
* #param array $arguments
* #param \Closure $renderChildrenClosure
* #param RenderingContextInterface $renderingContext
* #return mixed
*/
public static function renderStatic(
array $arguments,
\Closure $renderChildrenClosure,
RenderingContextInterface $renderingContext
) {
$for = $arguments['for'];
$controllerContext = $renderingContext->getControllerContext();
$validationResults = $controllerContext->getRequest()->getOriginalRequestMappingResults();
if ($validationResults !== null) {
$validationResults = $validationResults->forProperty($for);
}
$flattenedErrors = $validationResults->getFlattenedErrors();
return $flattenedErrors;
}
}
you can do:
{myExt:error() -> f:variable(name: 'errors')}}
or
{ff:error( for:"user" ) -> f:variable(name: 'errors')}}

Store JSON data into TEXT mysql column with doctrine

I have an entity with one TEXT (MySQL) attributes
<?php
namespace App\Entity;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\Table;
use Doctrine\ORM\Mapping\Index;
use ApiPlatform\Core\Annotation\ApiProperty;
/**
* #ApiResource(
* attributes={},
* collectionOperations={
* "get"={},
* "post"={
* "access_control"="is_granted('ROLE_COMPANY')"
* },
* },
* itemOperations={
* "get"={},
* "put"={"access_control"="is_granted('ROLE_COMPANY')"},
* }
* )
* #ORM\Entity(
* repositoryClass="App\Repository\SettingRepository",
* )
* #ORM\Table(
* indexes={#Index(name="domain_idx", columns={"domain"})}
* )
*/
class Setting
{
/**
* #var Uuid
* #ApiProperty(identifier=true)
* #ORM\Id
* #ORM\Column(type="string")
* #ORM\GeneratedValue(strategy="NONE")
*/
private $identifier;
/**
* #ORM\Column(type="text", nullable=true)
*/
private $data = array();
/**
* #ORM\Column(type="string", nullable=true)
*/
private $domain = array();
public function getData()
{
if($this->data == null) return array();
$data = unserialize($this->data);
return $data;
}
public function setData($data): self
{
$this->data = serialize($data);
return $this;
}
/**
* #return mixed
*/
public function getIdentifier()
{
return $this->identifier;
}
/**
* #param mixed $key
*/
public function setIdentifier($identifier): self
{
$this->identifier = $identifier;
return $this;
}
/**
* #return mixed
*/
public function getDomain()
{
return $this->domain;
}
/**
* #param mixed $domain
*/
public function setDomain($domain): self
{
$this->domain = $domain;
return $this;
}
}
If I try to invoke the service with the following parameter structure it works fine:
{
"data": "testData",
"identifier": "testIdentifier",
"domain": "domain1"
}
But If I would like to store an embedded JSON string, for example:
"data": {"temp": 123}
I receive the following error:
hydra:description": "The type of the \"data\" attribute must be \"string\", \"array\" given.",
I tried to convert the object into an string in the method setData. But this method will not be invoked. It seams, that the API-Platform detects the wrong type and throws the exception.
I found some comments, that it is necessary to decorate the property:
https://api-platform.com/docs/core/serialization/#decorating-a-serializer-and-adding-extra-data
Can anyone give me an example? It does not work!
Where is the right place to serialise and unserialise the property data?
Does anyone have an idea?
Kind regards
You need to set the column type to json in MySQL. It should behave as expected.
/**
* #var array Additional data describing the setting.
* #ORM\Column(type="json", nullable=true)
*/
private $data = null;
I think null is more consistent than an empty array, but that's your choice.

symfony2 inject service in config

I need to make functionality to validate JSON message, with particular validators, base on specific configuration.
I've got validator and constraints defined as services:
services:
validator.constraint.message.country_code:
class: RenamedBundle\Validator\Constraints\CountryCode
arguments: ...
validator.constraint.message.price_comma:
class: RenamedBundle\Validator\Constraints\PriceComma
arguments: ...
message.validator:
class: RenamedBundle\Service\Validator\MessageValidatorService
arguments: ['#validator']
calls:
- [addConstraint, ['#validator.constraint.message.country_code']]
- [addConstraint, ['#validator.constraint.message.price_comma']]
In DtoValidatorService I call validate()using constraints list.
The probl... challenge is that same JSON message can require validation only with few validators from list, depends on message properties ie. for Poland I want do validate all float values (in Poland separator is ',', not '.'). I've try to do this by config.yml.
renamed:
pritners:
warehouse_wa:
characteristic:
country: 'pl'
source: 'hq-pl'
validators:
- '#validator.constraint.message.country_code'
- '#validator.constraint.message.price_comma'
warehouse_ny:
characteristic:
country: 'us'
source: 'hq-us'
validators:
- '#validator.constraint.message.country_code'
I've added extension:
class Configuration implements ConfigurationInterface
{
/**
* {#inheritDoc}
*
* #throws \RuntimeException
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('renamed');
$rootNode
->children()
->arrayNode('printers')
->useAttributeAsKey('name')
->prototype('array')
->children()
->arrayNode('characteristic')
->children()
->scalarNode('country')->end()
->scalarNode('source')->end()
->end()
->end()
->end()
->children()
->arrayNode('validators')
->prototype('scalar')->end()
->end()
->end()
->end()
->end()
->end();
return $treeBuilder;
}
}
class RenamedExtension extends Extension
{
/**
* {#inheritDoc}
* #throws \Exception
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$container->setParameter('printers', $config['printers']);
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.yml');
}
}
This configuration works, but problem is when i pass '%printers%' parameter into service, I recieve list of services names:
Array
(
[0] => #validator.constraint.message.country_code
)
but when I pass constraint I got object.
array(1) {
[0] =>
class RenamedBundle\Validator\Constraints\CountryCode#688 (5) {
...
}
}
I'm in dead end now. How can I parameterized printers configuration and avoid passing inline/hardcode validator class name. Calling services in paremeters section is not allowed. Calling them in configuration provide me additional controll and validation.
Maybe someone got better solution?
edit:
According to #Artur Vesker suggestion, I change extension load method implementation.
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$printers = [];
foreach ($config['printers'] as $printerName => $printerConfig) {
$constraints = [];
foreach($printerConfig['valdiators'] as $constraintName) {
$constraintName = ltrim($constraintName, '#');
$constraints[] = new Reference($constraintName);
}
$printerConfig['valdiators'] = $constraints;
$printers[$printerName] = $printerConfig;
}
$container->setParameter('printers', $printers);
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.yml');
}
trying to build cache I got:
Symfony\Component\DependencyInjection\Exception\InvalidArgumentException
You cannot dump a container with parameters that contain references to other services
It looks my approach in not allowed in symfony world ;]
Use Reference
Set just ids in config:
validators:
- 'validator.constraint.message.country_code'
- 'validator.constraint.message.price_comma'
And create parameter with Reference in you Extension
$validators = array_map(function($id) {
return new Reference($id);
}, $config['pritners.warehouse_wa.validators']);
$messageValidatorDefinition = new Definition('RenamedBundle\Service\Validator\MessageValidatorService', [new Reference('validator)]);
foreach ($validators as $validator) {
messageValidatorDefinition->addMethodCall('addConstraint', [$validator])
}
Thanks Artur Vesker, Your solution works for me.
I tried to keep message.validator in services.yml (I want to have PHPStorm hints) and get them in extension by $container->getDefinition('message.validator'), but in this way addMethodCall not working. So anyone that will try this way, it will not work, you must create service dynamillacy as Artur suggest.
My full code:
- same class Configuration implements ConfigurationInterface
- same config.yml
- removed message.validator from services.yml
- in messageValidator I decide to group constraints by printer name
/**
* Class MessageValidatoService
* #package RenamedBundle\Service
*/
class MessageValidatoService
{
/** PrinterConfigurationDto[] */
protected $printersConfig;
/**
* array of constraints for preValidator grouped by printer name ex:
* [
* 'printer_name' => [Constraint1, Constraint2]
* ]
* #var array
*/
protected $constraints;
/**
* MessageValidatorService constructor.
*
* #param array $printersConfiguration
* #param Serializer $serializer
*
* #throws \RuntimeException
*/
public function __construct(array $printersConfiguration, Serializer $serializer)
{
$this->serializer = $serializer;
$this->constraints = [];
$this->printersConfig = [];
foreach ($printersConfiguration as $printerConfig) {
/** #var PrinterConfigurationDto $configDto */
$configDto = $this->serializer->fromArray(
$printerConfig,
'RenamedBundle\Dto\PrinterConfiguration\PrinterConfigurationDto'
);
$this->printersConfig[] = $configDto;
}
}
/**
* #param string $printerName
* #param Constraint $constraint
*
* #return $this
*/
public function addConstraint($printerName, Constraint $constraint)
{
$this->constraints[$printerName][] = $constraint;
return $this;
}
/**
* Return PrinterConfigurationDto, or throw RuntimeException if none configuration fir to ReceiptDto parameters.
*
* #param ReceiptDto $receiptDto
*
* #return PrinterConfigurationDto
*
* #throws \RuntimeException
* #throws \OutOfRangeException
*/
protected function getPrinterConfig($receiptDto)
{
$countryCodes = $receiptDto->getCountryCodes();
if (array_key_exists($receiptDto->getCountryId(), $countryCodes) === false) {
throw new \OutOfRangeException('Missing country code for country id:' . $receiptDto->getCountryId());
}
/** #var PrinterConfigurationDto $printerConfig */
foreach ($this->printersConfig as $printerConfig) {
if ($printerConfig->getSourceApp() === $receiptDto->getSourceApp()
&& $printerConfig->getCountry() === $countryCodes[$receiptDto->getCountryId()]
) {
return $printerConfig;
}
}
throw new \RuntimeException(
'No printer configuration found for app:' . $receiptDto->getSourceApp()
. ', country id: ' . $receiptDto->getCountryId()
);
}
/**
* #param ReceiptDto $receiptDto
*
* #return Constraint[]
*
* #throws \RuntimeException
* #throws \OutOfRangeException
*/
public function getValidatorConstraints(ReceiptDto $receiptDto)
{
$printerConfig = $this->getPrinterConfig($receiptDto);
if (array_key_exists($printerConfig->getName(), $this->constraints) === false) {
return [];
}
return $this->constraints[$printerConfig->getName()];
}
}
/**
* Class RenamedExtension
* #package RenamedBundle\DependencyInjection
*/
class RenamedExtension extends Extension
{
/**
* {#inheritDoc}
* #throws \Exception
* #throws ServiceNotFoundException
* #throws InvalidArgumentException
* #throws BadMethodCallException
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
//set parameters before load services
//rewrite printers configuration from RenamedBundle\Resources\printers.yml
//structure changes must be implemented also in RenamedBundle\Dto\PrinterConfiguration\PrinterConfigurationDto
$printers = [];
foreach ($config['printers'] as $printerName => $printerConfig) {
$printers[] = [
'name' => $printerName,
'country' => $printerConfig['characteristic']['country'],
'source_app' => $printerConfig['characteristic']['source_app'],
];
}
$container->setParameter('printers', $printers);
//load services, add constraints
$loader = new YamlFileLoader($container, new FileLocator(__DIR__ . '/../Resources/config'));
$loader->load('services.yml');
$definition = new Definition(PrinterManagerService::class);
$definition->addArgument('%printers%');
$definition->addArgument(new Reference('serializer'));
foreach ($config['validators'] as $printerName => $printerConfig) {
if (array_key_exists('validators', $printerConfig)
&& is_array($printerConfig['validators'])
) {
foreach ($printerConfig['validators'] as $constraintName) {
$constraint = new Reference(ltrim($constraintName, '#'));
$definition->addMethodCall('addConstraint', [$printerName, $constraint]);
}
}
}
$container->setDefinition('message.validator', $definition);
}
}

ZF2 fileupload not required with annotationbuilder

I'm stuck at a problem with ZendFramework 2, annotationbuilder and fileupload.
for at contact form i want user the choice to upload a file.
I got everything to work except the file upload, if there is no file a get the
error:
File was not uploaded
I'm using annotationbuilder to create the form. some annotations is cut out with a space for testing. but did not help.
the Annotation class:
<?php
/**
* #Annotation\Name("message")
* #Annotation\Hydrator("Zend\Stdlib\Hydrator\ObjectProperty")
* #ORM\Entity
* #ORM\Table(name="contact_message")
*/
class Message {
/**
* #Annotation\Exclude()
*
* #ORM\Id
* #ORM\GeneratedValue
* #ORM\Column(type="integer")
* #var integer
*/
private $id;
/**
* #Annotation\Type("Zend\Form\Element\Select")
* #Annotation\Flags({"priority": 600})
* #Annotation\Required({"required":"true" })
* #Annotation\Filter({"name":"StringTrim"})
* # Annotation\Validator({"name":"StringLength"})
* #Annotation\Options({"label":"About:"})
* #Annotation\Attributes({"options":{"1":"PlaceHolder","2":"Test"}})
*
* #ORM\Column(type="string")
* #var String
*/
private $about;
/**
* #Annotation\Type("Zend\Form\Element\Text")
* #Annotation\Flags({"priority": 500})
* #Annotation\Required({"required":"true" })
* #Annotation\Filter({"name":"StripTags"})
* # Annotation\Validator({"name":"EmailAddress"})
* #Annotation\Options({"label":"Name:"})
* #Annotation\Attributes({"required": true,"placeholder": "Your name ... "})
*
* #ORM\Column(type="string")
* #var String
*/
private $name;
/**
* #Annotation\Type("Zend\Form\Element\Text")
* #Annotation\Flags({"priority": 500})
* #Annotation\Required({"required":"true" })
* #Annotation\Filter({"name":"StripTags"})
* # Annotation\Validator({"name":"EmailAddress"})
* #Annotation\Options({"label":"Subject:"})
* #Annotation\Attributes({"required": true,"placeholder": "Subject ... "})
*
* #ORM\Column(type="string")
* #var String
*/
private $subject;
/**
* #Annotation\Type("Zend\Form\Element\File")
* #Annotation\Flags({"priority": 500})
* # Annotation\Required({"required":false })
* # Annotation\Filter({"name":"StringTrim","filerenameupload":{"target": "./img","randomize":true}})
* # Annotation\Filter({"name":"StripTags"})
* # Annotation\Validator({"name":"StringLength"})
* #Annotation\Options({"label":"File:"})
* #Annotation\Attributes({"required": false})
*
* #ORM\Column(type="string")
* #var String
*/
private $file;
/**
* #Annotation\Type("Zend\Form\Element\Textarea")
* #Annotation\Flags({"priority": 500})
* # Annotation\Required({"required":"true" })
* #Annotation\Filter({"name":"StripTags"})
* # Annotation\Validator({"name":"EmailAddress"})
* #Annotation\Options({"label":"Message:"})
* #Annotation\Attributes({"required": true,"placeholder": "Message ... "})
*
* #ORM\Column(type="string")
* #var String
*/
private $message;
/**
* WARNING USING THESE IS NOT SAFE. there is no checking on the data and you need to know what
* you are doing when using these.
* But it a great function for lazy people ;)
*
* #param ANY $value
* #param ANY $key
* #return $value
*/
public function __set($value,$key){
return $this->$key = $value;
}
/**
* WARNING USING THESE IS NOT SAFE. there is no checking on the data and you need to know what
* you are doing when using these.
* But it a great function for lazy people ;)
*
* #param ANY $value
* #param ANY $key
* #return $value
*/
public function __get($key){
return $this->$key;
}
/**
* WARNING USING THESE IS NOT SAFE. there is no checking on the data and you need to know what
* you are doing when using these.
* This is used to exchange data from form and more when need to store data in the database.
* and again ist made lazy, by using foreach without data checks
*
* #param ANY $value
* #param ANY $key
* #return $value
*/
public function populate($array){
foreach ($array as $key => $var){
$this->$key = $var;
}
}
/**
* Get an array copy of object
*
* #return array
*/
public function getArrayCopy()
{
return get_object_vars($this);
}
}
?>
and the add Action in my controller:
<?php
use Zend\View\Model\ViewModel;
use Zend\Form\Annotation\AnnotationBuilder;
use Contact\Entity\Contact;
use Contact\Entity\Company;
use Contact\Entity\Message;
use Contact\Controller\EntityUsingController;
class MessageController extends EntityUsingController {
public function addAction(){
$message = new Message();
$builder = new AnnotationBuilder();
$form = $builder->createForm($message);
$form->bind($message);
$request = $this->getRequest();
if ($request->isPost()) {
$form->bind($message);
$requestData = array_merge_recursive((array) $request->getPost(),(array) $request->getFiles());
$form->setData($requestData);
var_dump($request->getFiles());
if ($form->isValid()) {
$em = $this->getEntityManager();
$em->persist($message);
$em->flush();
$this->flashMessenger()->addMessage('Contact Saved');
return $this->redirect()->toRoute('contact');
}
}
return new ViewModel(array(
'form' => $form
));
}
private function storeFile($file){
if (!$this->getConfiguration('fileupload')){
return null;
}
$fileBank = $this->getServiceLocator()->get('FileRepository');
$entity = $fileBank->save('/tmp/myfile.jpg');
}
}
?>
I hope anyone can help my get around this problem.
This seems to be a bug in the annotation builder.
I found a lot of places on the net that confirmed that i should be correct.
so i ended up hacking it by adding the file input after the form was build.
if ($this->getConfiguration('fileupload')){
$companyForm->add(array(
'name' => 'file',
'priority' => 300,
'type' => 'file',
'options' => array(
'label' => 'File:',
),
),array('priority' => 300));
}
checks if the configuration allows for file upload. an extra feature I put in now that I could not set the file upload as an annotation
If you're still interested in another way:
You can try the AllowEmpty annotation:
* #Annotation\AllowEmpty(true)
Or you can try to disable the validator for that field in the controller:
$form->getInputFilter()->remove('file');

Resources