I don't understand why some constraints does not insert name of property in error message after validation. I have this entity class:
<?php
namespace AC\OperaBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use AC\UserBundle\Entity\Utente;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Class Episodio
* #package AC\OperaBundle\Entity
* #ORM\Entity(repositoryClass="AC\OperaBundle\Repository\EpisodioRepository")
* * #ORM\Table(
* name="ac_Episodio",
* uniqueConstraints={#ORM\UniqueConstraint(name="unique_idx", columns={"opera", "numero_episodio", "extra"})},
* indexes={ #ORM\Index(name="opera_idx", columns={"opera"}),
* #ORM\Index(name="numero_episodio_idx", columns={"numero_episodio"}),
* #ORM\Index(name="extra_idx", columns={"extra"}),
* #ORM\Index(name="attivo_idx", columns={"attivo"}) })
*/
class Episodio {
/**
* #var int
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #var Opera
*
* #ORM\ManyToOne(targetEntity="AC\OperaBundle\Entity\Opera", inversedBy="episodi")
* #ORM\JoinColumn(name="opera", referencedColumnName="id", nullable=false)
*/
protected $opera;
/**
* #var string
*
* #ORM\Column(name="numero_episodio", type="string", length=5, nullable=false)
*/
protected $numero_episodio;
/**
* #var string
*
* #ORM\Column(name="extra", type="string", length=30, nullable=false)
*/
protected $extra;
/**
* #var string
*
* #ORM\Column(name="titolo_italiano", type="string", length=150, nullable=false)
* #Assert\NotBlank()
*/
protected $titolo_italiano;
/**
* #var string
*
* #ORM\Column(name="titolo_originale", type="string", length=150, nullable=false)
* #Assert\NotBlank()
*/
protected $titolo_originale;
/**
* #var \DateTime
*
* #ORM\Column(name="data_ita", type="date", nullable=true)
* #Assert\Date()
*/
protected $data_ita;
/**
* #var \DateTime
*
* #ORM\Column(name="data_jap", type="date", nullable=true)
* #Assert\Date()
*/
protected $data_jap;
/**
* #var int
*
* #ORM\Column(name="durata", type="smallint", nullable=false, options={"default" = 0})
*/
protected $durata;
/**
* #var string
*
* #ORM\Column(name="trama", type="text", nullable=false)
*/
protected $trama;
/**
* #var int
*
* #ORM\Column(name="ordine", type="smallint", nullable=false, options={"default" = 0})
*/
protected $ordine;
/**
* #var int
*
* #ORM\Column(name="promosso", type="integer", nullable=false, options={"default" = 0})
*/
protected $promosso;
/**
* #var int
*
* #ORM\Column(name="rimandato", type="integer", nullable=false, options={"default" = 0})
*/
protected $rimandato;
/**
* #var int
*
* #ORM\Column(name="bocciato", type="integer", nullable=false, options={"default" = 0})
*/
protected $bocciato;
/**
* #var boolean
*
* #ORM\Column(name="fansub", type="boolean", nullable=false)
*/
protected $fansub;
/**
* #var boolean
*
* #ORM\Column(name="attivo", type="boolean", nullable=false)
*/
protected $attivo;
/**
* #var \DateTime
*
* #ORM\Column(name="data_aggiornamento", type="date")
*/
protected $data_aggiornamento;
/**
* #var Utente
*
* #ORM\ManyToOne(targetEntity="AC\UserBundle\Entity\Utente")
* #ORM\JoinColumn(name="utente_aggiornamento", referencedColumnName="id", nullable=true)
*/
protected $utente_aggiornamento;
/**
* #param boolean $attivo
*/
public function setAttivo($attivo)
{
$this->attivo = $attivo;
}
/**
* #return boolean
*/
public function getAttivo()
{
return $this->attivo;
}
/**
* #param int $bocciato
*/
public function setBocciato($bocciato)
{
$this->bocciato = $bocciato;
}
/**
* #return int
*/
public function getBocciato()
{
return $this->bocciato;
}
/**
* #param \DateTime $data_aggiornamento
*/
public function setDataAggiornamento($data_aggiornamento)
{
$this->data_aggiornamento = $data_aggiornamento;
}
/**
* #return \DateTime
*/
public function getDataAggiornamento()
{
return $this->data_aggiornamento;
}
/**
* #param \DateTime $data_ita
*/
public function setDataIta($data_ita)
{
$this->data_ita = $data_ita;
}
/**
* #return \DateTime
*/
public function getDataIta()
{
return $this->data_ita;
}
/**
* #param \DateTime $data_jap
*/
public function setDataJap($data_jap)
{
$this->data_jap = $data_jap;
}
/**
* #return \DateTime
*/
public function getDataJap()
{
return $this->data_jap;
}
/**
* #param int $durata
*/
public function setDurata($durata)
{
$this->durata = $durata;
}
/**
* #return int
*/
public function getDurata()
{
return $this->durata;
}
/**
* #param string $extra
*/
public function setExtra($extra)
{
$this->extra = $extra;
}
/**
* #return string
*/
public function getExtra()
{
return $this->extra;
}
/**
* #param boolean $fansub
*/
public function setFansub($fansub)
{
$this->fansub = $fansub;
}
/**
* #return boolean
*/
public function getFansub()
{
return $this->fansub;
}
/**
* #param int $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* #return int
*/
public function getId()
{
return $this->id;
}
/**
* #param string $numero_episodio
*/
public function setNumeroEpisodio($numero_episodio)
{
$this->numero_episodio = $numero_episodio;
}
/**
* #return string
*/
public function getNumeroEpisodio()
{
return $this->numero_episodio;
}
/**
* #param \AC\OperaBundle\Entity\Opera $opera
*/
public function setOpera($opera)
{
$this->opera = $opera;
}
/**
* #return \AC\OperaBundle\Entity\Opera
*/
public function getOpera()
{
return $this->opera;
}
/**
* #param int $ordine
*/
public function setOrdine($ordine)
{
$this->ordine = $ordine;
}
/**
* #return int
*/
public function getOrdine()
{
return $this->ordine;
}
/**
* #param int $promosso
*/
public function setPromosso($promosso)
{
$this->promosso = $promosso;
}
/**
* #return int
*/
public function getPromosso()
{
return $this->promosso;
}
/**
* #param int $rimandato
*/
public function setRimandato($rimandato)
{
$this->rimandato = $rimandato;
}
/**
* #return int
*/
public function getRimandato()
{
return $this->rimandato;
}
/**
* #param string $titolo_italiano
*/
public function setTitoloItaliano($titolo_italiano)
{
$this->titolo_italiano = $titolo_italiano;
}
/**
* #return string
*/
public function getTitoloItaliano()
{
return $this->titolo_italiano;
}
/**
* #param string $titolo_originale
*/
public function setTitoloOriginale($titolo_originale)
{
$this->titolo_originale = $titolo_originale;
}
/**
* #return string
*/
public function getTitoloOriginale()
{
return $this->titolo_originale;
}
/**
* #param string $trama
*/
public function setTrama($trama)
{
$this->trama = $trama;
}
/**
* #return string
*/
public function getTrama()
{
return $this->trama;
}
/**
* #param \AC\UserBundle\Entity\Utente $utente_aggiornamento
*/
public function setUtenteAggiornamento($utente_aggiornamento)
{
$this->utente_aggiornamento = $utente_aggiornamento;
}
/**
* #return \AC\UserBundle\Entity\Utente
*/
public function getUtenteAggiornamento()
{
return $this->utente_aggiornamento;
}
}
In the controller perform the classi call at the $form->isValid() method to check validation. If there are errors i call $form->getErrorsAsString() and this is the result:
ERROR: This value should not be blank.
ERROR: This value should not be blank.
numeroEpisodio:
No errors
titoloItaliano:
No errors
titoloOriginale:
No errors
dataIta:
ERROR: This value is not valid.
dataJap:
ERROR: This value is not valid.
durata:
No errors
trama:
No errors
extra:
No errors
fansub:
No errors
The property that use #Assert\NotBlank() dose not put property name in error message! And for this reason i have the first two error line with e generic:
ERROR: This value should not be blank.
ERROR: This value should not be blank.
I i don't know who is the property that failed the validation. I look in the source code of Symfony Component and i see that for not blank constraint:
/**
* #author Bernhard Schussek <bschussek#gmail.com>
*
* #api
*/
class NotBlankValidator extends ConstraintValidator
{
/**
* {#inheritdoc}
*/
public function validate($value, Constraint $constraint)
{
if (!$constraint instanceof NotBlank) {
throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\NotBlank');
}
if (false === $value || (empty($value) && '0' != $value)) {
$this->context->addViolation($constraint->message);
}
}
}
And for data constraint:
/**
* #author Bernhard Schussek <bschussek#gmail.com>
*
* #api
*/
class DateValidator extends ConstraintValidator
{
const PATTERN = '/^(\d{4})-(\d{2})-(\d{2})$/';
/**
* {#inheritdoc}
*/
public function validate($value, Constraint $constraint)
{
if (!$constraint instanceof Date) {
throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Date');
}
if (null === $value || '' === $value || $value instanceof \DateTime) {
return;
}
if (!is_scalar($value) && !(is_object($value) && method_exists($value, '__toString'))) {
throw new UnexpectedTypeException($value, 'string');
}
$value = (string) $value;
if (!preg_match(static::PATTERN, $value, $matches) || !checkdate($matches[2], $matches[3], $matches[1])) {
$this->context->addViolation($constraint->message, array('{{ value }}' => $value));
}
}
}
The important difference is $this->context->addViolation($constraint->message); VS $this->context->addViolation($constraint->message, array('{{ value }}' => $value));
Why?
This is core part of controller
if ($request->getMethod() == 'POST') {
try {
$form->handleRequest($request);
if ($form->isValid()) {
/* #var $item Episodio */
$item = $form->getData();
$em->persist($item);
$em->flush();
$msg = new Message(true, Message::OK_MESSAGE);
} else {
$msg = new Message(false, Message::KO_MESSAGE);
$errors = Utility::getErrorMessages($form);
$msg->setData($errors);
}
} catch (\Exception $ex) {
$msg = new Message(false, $ex->getMessage());
}
return new Response($this->get('jms_serializer')->serialize($msg, 'json'));
}
This is utility class that fetch error from form
class Utility {
static function getErrorMessages(\Symfony\Component\Form\Form $form) {
$errors = array();
foreach ($form->getErrors() as $key => $error) {
$template = $error->getMessageTemplate();
$parameters = $error->getMessageParameters();
foreach($parameters as $var => $value){
$template = str_replace($var, $value, $template);
}
$errors[$key] = $template;
}
//if ($form->hasChildren()) {
foreach ($form->all() as $child) {
if (!$child->isValid()) {
$errors[$child->getName()] = Utility::getErrorMessages($child);
}
}
//}
return $errors;
}
}
Form Class
class EpisodioForm extends AbstractType {
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('numeroEpisodio', 'text');
$builder->add('titoloItaliano', 'text',array());
$builder->add('titoloOriginale', 'text');
$builder->add('dataIta', 'date', array('widget' => 'single_text', 'format' => 'dd/MM/yyyy'));
$builder->add('dataJap', 'date', array('widget' => 'single_text', 'format' => 'dd/MM/yyyy'));
$builder->add('durata', 'text');
$builder->add('trama', 'textarea');
$builder->add('extra', 'text');
$builder->add('fansub', 'checkbox');
}
/**
* Returns the name of this type.
*
* #return string The name of this type
*/
public function getName()
{
return "episodio_form";
}
}
The version of framework is Symfony 2.4
Why $this->context->addViolation($constraint->message); VS $this->context->addViolation($constraint->message, array('{{ value }}' => $value));?
This is because the date constraint validator shows the value which failed to validate in the error message, e.g.
45.04.2014 is not a valid date.
whereas the NotBlank constraint validator doesn't need to, since the value causing the error is always empty.
Putting the property name in the error message
This could be achieved:
by changing the annotations for the constraints in your entity to something like:
class Episodio {
/**
* #Assert\NotBlank(message="'titolo_italiano' should not be blank.")
*/
protected $titolo_italiano;
/**
* #Assert\NotBlank(message="'titolo_originale' should not be blank.")
*/
protected $titolo_originale;
}
I left out the column definitions and the other fields in the entity for the sake of readability.
OR by defining a custom validator which passes the name of the property to the error message:
The constraint:
class MyCustomNotBlank extends NotBlank
{
public $message = "'{{ propertyName }}' should not be blank.";
}
The validator:
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class MyCustomNotBlankValidator extends ConstraintValidator
{
public function validate($value, Constraint $constraint)
{
if (!$value) {
$this->context->addViolation(
$constraint->message,
array('{{ propertyName}}' => $this->context->getPropertyPath())
);
}
}
}
This shows you how to define a custom validation constraint:
http://symfony.com/doc/current/cookbook/validation/custom_constraint.html
Obtaining a key-value array with property name and error message
Afaik, there is no function in Symfony2's form component which does that, so it has to be implemented.
See https://stackoverflow.com/a/13763053/277106 . You can add that function to a service for reusability. In your (AJAX) controller you can then do:
public function someAction(Request $request)
{
$errors = array();
$form = $this->createForm(new MyType);
if (!$form->bindRequest($request)->isValid()) {
$errors = $this->myFormService->getErrorMessages($form);
}
else {
// save the entity
}
return JsonResponse($errors);
}
Related
I'm stuck with this problem. I try to upload one or more picture for one entity with a collection but when I submit my form I've got this error :
Symfony\Component\Validator\ConstraintViolation
Object(Symfony\Component\Form\Form).data.imagearticle[0].Article = null
It's because in my entity ImageArticle I put this :
namespace AD\PlatformBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\Validator\Constraints as Assert;
use AD\PlatformBundle\Entity\Article;
/**
* ImageArticle
*
* #ORM\Table()
* #ORM\Entity()
* #ORM\HasLifecycleCallbacks
*/
class ImageArticle
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="url", type="string", length=255)
*/
private $url;
/**
* #var string
*
* #ORM\Column(name="alt", type="string", length=255)
*/
private $alt;
/**
* #var File
*
* #Assert\File(
* maxSize = "1M",
* mimeTypes = {
* "image/jpeg",
* "image/gif",
* "image/png",
* },
* maxSizeMessage = "La taille maximum du fichier doit etre inférieur ou égale à 1MB. Pour reduire sa taille vous pouvez utiliser le site : compressjpeg.com",
* mimeTypesMessage = "Seulement les fichiers .jpeg / .gif /.png sont acceptés"
* )
*/
private $file;
private $tempFileName;
/**
* #var Article
* #ORM\ManyToOne(targetEntity="AD\PlatformBundle\Entity\Article", inversedBy="imagearticle")
* #ORM\JoinColumn(nullable=false)
* #Assert\NotNull()
*/
private $Article;
public function getFile()
{
return $this->file;
}
public function setFile(UploadedFile $file)
{
$this->file = $file;
if (null !== $this->url)
{
$this->tempFileName = $this->url;
$this->url=null;
$this->alt=null;
}
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set url
*
* #param string $url
*
* #return ImageArticle
*/
public function setUrl($url)
{
$this->url = $url;
return $this;
}
/**
* Get url
*
* #return string
*/
public function getUrl()
{
return $this->url;
}
/**
* Set alt
*
* #param string $alt
*
* #return ImageArticle
*/
public function setAlt($alt)
{
$this->alt = $alt;
return $this;
}
/**
* Get alt
*
* #return string
*/
public function getAlt()
{
return $this->alt;
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function preUpload()
{
if (null === $this->file)
{
return;
}
//On add un extension pour le fichier.
$this->url = $this->file->guessExtension();
//Le alt est le nom du fichier du client.
$this->alt= $this->file->getClientOriginalName();
}
/**
*
* #ORM\PostPersist()
* #ORM\PostUpdate()
*
*/
public function upload()
{
if(null=== $this->file)
{
return;
}
//Si ancien fichier on supprime
if(null !== $this->tempFileName)
{
$oldFile = $this->getUploadRootDir().'/'.$this->id.'.'.$this->tempFileName;
if (file_exists($oldFile))
{
unlink($oldFile);
}
}
//On deplace
$this->file->move
(
$this->getUploadRootDir(),
$this->id.'.'.$this->url
);
// chmod($this->getUploadRootDir().'/'.$this->id.'.'.$this->url,644);
}
/**
*#ORM\PreRemove()
*/
public function preRemoveUpload()
{
$this->tempFileName = $this->getUploadRootDir().'/'.$this->id.'.'.$this->url;
}
/**
*
* #ORM\PostRemove()
*/
public function removeUpload()
{
if(file_exists($this->tempFileName))
{
unlink($this->tempFileName);
}
}
public function getUploadDir()
{
return 'upload/img/blog/';
}
protected function getUploadRootDir()
{
return __DIR__.'/../../../../web/'.$this->getUploadDir();
}
public function __toString()
{
return $this->getUploadDir().$this->id.'.'.$this->getUrl();
}
/**
* Set source
*
* #param string $source
*
* #return Image
*/
/**
* Set article
*
* #param \AD\PlatformBundle\Entity\Article $article
*
* #return ImageArticle
*/
public function setArticle(\AD\PlatformBundle\Entity\Article $article = null)
{
$this->article = $article;
return $this;
}
/**
* Get article
*
* #return \AD\PlatformBundle\Entity\Article
*/
public function getArticle()
{
dump($this->article);
return $this->article;
}
But when I remove this Assert\NotNull my error is "Column article_id cannot be null"
This is my Article entity :
<?php
namespace AD\PlatformBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Validator\Constraints as Assert;
/**
* Article
*
* #ORM\Table()
* #ORM\Entity
*/
class Article
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="titre1", type="string", length=255)
*/
private $titre1;
/**
* #var string
*
* #ORM\Column(name="titre2", type="string", length=255)
*/
private $titre2;
/**
* #var string
*
* #ORM\Column(name="description", type="text")
*/
private $description;
/**
* #ORM\ManyToMany(targetEntity="AD\UserBundle\Entity\User")
* #ORM\JoinColumn(nullable=false)
*/
private $user;
/**
*
* #ORM\OneToMany(targetEntity="AD\PlatformBundle\Entity\ImageArticle", mappedBy="article", cascade="all", orphanRemoval=true)
* #Assert\Valid()
* #ORM\OrderBy({"position" = "ASC"})
*
*/
private $imagearticle;
/**
* #Gedmo\Slug(fields={"titre1"})
* #ORM\Column(length=128, unique=true)
*/
private $slugurl;
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set titre1
*
* #param string $titre1
*
* #return Article
*/
public function setTitre1($titre1)
{
$this->titre1 = $titre1;
return $this;
}
/**
* Get titre1
*
* #return string
*/
public function getTitre1()
{
return $this->titre1;
}
/**
* Set titre2
*
* #param string $titre2
*
* #return Article
*/
public function setTitre2($titre2)
{
$this->titre2 = $titre2;
return $this;
}
/**
* Get titre2
*
* #return string
*/
public function getTitre2()
{
return $this->titre2;
}
/**
* Set description
*
* #param string $description
*
* #return Article
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Get description
*
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set user
*
* #param \AD\UserBundle\Entity\User $user
*
* #return Article
*/
public function setUser(\AD\UserBundle\Entity\User $user)
{
$this->user = $user;
return $this;
}
/**
* Get user
*
* #return \AD\UserBundle\Entity\User
*/
public function getUser()
{
return $this->user;
}
/**
* Set imagearticle
*
* #param \AD\PlatformBundle\Entity\ImageArticle $imagearticle
*
* #return Article
*/
public function setImagearticle(\AD\PlatformBundle\Entity\ImageArticle $imagearticle = null)
{
$this->imagearticle = $imagearticle;
return $this;
}
/**
* Get imagearticle
*
* #return \AD\PlatformBundle\Entity\ImageArticle
*/
public function getImagearticle()
{
return $this->imagearticle;
}
/**
* Constructor
*/
public function __construct()
{
$this->user = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Set slugurl
*
* #param string $slugurl
*
* #return Article
*/
public function setSlugurl($slugurl)
{
$this->slugurl = $slugurl;
return $this;
}
/**
* Get slugurl
*
* #return string
*/
public function getSlugurl()
{
return $this->slugurl;
}
/**
* Add user
*
* #param \AD\UserBundle\Entity\User $user
*
* #return Article
*/
public function addUser(\AD\UserBundle\Entity\User $user)
{
$this->user[] = $user;
return $this;
}
/**
* Remove user
*
* #param \AD\UserBundle\Entity\User $user
*/
public function removeUser(\AD\UserBundle\Entity\User $user)
{
$this->user->removeElement($user);
}
/**
* Add imagearticle
*
* #param \AD\PlatformBundle\Entity\ImageArticle $imagearticle
*
* #return Article
*/
public function addImagearticle(\AD\PlatformBundle\Entity\ImageArticle $imagearticle)
{
$this->imagearticle[] = $imagearticle;
return $this;
}
/**
* Remove imagearticle
*
* #param \AD\PlatformBundle\Entity\ImageArticle $imagearticle
*/
public function removeImagearticle(\AD\PlatformBundle\Entity\ImageArticle $imagearticle)
{
$this->imagearticle->removeElement($imagearticle);
}
}
Thx for your help!
My controller :
public function newArticleAction(Request $request)
{
$article= new Article();
$form = $this->get('form.factory')->create(new \AD\PlatformBundle\Form\ArticleType(), $article);
if($form->handleRequest($request)->isValid())
{
$em = $this->getDoctrine()->getManager();
$em->persist($article);
$em->flush();
$request->getSession()->getFlashBag()->add('notice', 'Annonce enregistrée ! :)');
return $this->redirect($this->generateUrl('va_platform_blog'));
}
return $this->render('ADPlatformBundle:Cars:newarticle.html.twig', array(
'form' =>$form->createView(),
));
}
And my form ArticleType :
class ArticleType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('titre1')
->add('titre2')
->add('description', 'textarea', array('required' => false))
->add('imagearticle', 'collection', array(
'type' => new ImageArticleType(),
'allow_add' => true,
'allow_delete' => true,
'required' => true,
'by_reference' => false,
))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AD\PlatformBundle\Entity\Article'
));
}
/**
* #return string
*/
public function getName()
{
return 'ad_platformbundle_article';
}
}
ImageArticleType
namespace AD\PlatformBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class ImageArticleType extends AbstractType
{
/**
* #param FormBuilderInterface $builder
* #param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('file', 'file', array('label' => 'Choisir mon images'))
;
}
/**
* #param OptionsResolverInterface $resolver
*/
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'AD\PlatformBundle\Entity\ImageArticle'
));
}
/**
* #return string
*/
public function getName()
{
return 'ad_platformbundle_imagearticle';
}
Here is the solution.
In ImageArticle.php:
/**
* #var Article
* #ORM\ManyToOne(targetEntity="AD\PlatformBundle\Entity\Article", inversedBy="imagearticle")
* #ORM\JoinColumn(nullable=false)
* #Assert\NotNull()
*/
private $article; //previously $Article
In Article.php:
/**
*
* #ORM\OneToMany(targetEntity="AD\PlatformBundle\Entity\ImageArticle", mappedBy="article", cascade="all", orphanRemoval=true)
* #Assert\Valid()
*
*/
private $imagearticle; // remove #ORM\OrderBy({"position" = "ASC"}) since there is no position property
public function __construct()
{
$this->user = new \Doctrine\Common\Collections\ArrayCollection();
$this->imagearticle = new \Doctrine\Common\Collections\ArrayCollection(); //instanciate as an ArrayCollection when a new instance of Article is created
}
/**
* Add imagearticle
*
* #param \AD\PlatformBundle\Entity\ImageArticle $imagearticle
*
* #return Article
*/
public function addImagearticle(\AD\PlatformBundle\Entity\ImageArticle $imagearticle)
{
$imagearticle->setArticle($this); //since doctrine only checks owning side you need to do this to keep data in sync
$this->imagearticle[] = $imagearticle;
return $this;
}
/**
* Remove imagearticle
*
* #param \AD\PlatformBundle\Entity\ImageArticle $imagearticle
*/
public function removeImagearticle(\AD\PlatformBundle\Entity\ImageArticle $imagearticle)
{
$imagearticle->setArticle(); //same reason than above
$this->imagearticle->removeElement($imagearticle);
return $this;
}
I also recommend you to remove method setImagearticle() since image article is a collection and not an object, you should not have to use it.
Use camelCase to name your variable and method (so it should be $imageArticle and not imagearticle) this is a good practice to make your code more readable by others.
Finally use plural when you are working with collections (i.e. users instead of user) so you immediatly know what you are working with (another good practice).
I'm implementing a search on a website and for simplicity i've decided to create a class that does the hard work.
Basically my class takes the EntityManager and the Entities in which i want to search and creates the DQL and executes the query. For normal entities this works totally fine but when i pass the User entity (Extended from fos user bundle entity) i get this error :
[Semantical Error] line 0, col 139 near 'last_login LIKE': Error: Class Soundmerger\UserBundle\Entity\User has no field or association named last_login
The dql query generated seems fine and as it works for the other entities i doubt it comes form there.
Here is my Search class :
use Doctrine\Common\Util\Debug;
use Doctrine\ORM\EntityManager;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Query;
class Search {
private $em;
private $searchables;
public function __construct(EntityManager $em, ArrayCollection $searchables){
$this->em = $em;
$this->searchables = $searchables;
}
public function search($query){
$words = explode("+", $query);
$qb = array();
$results = array();
foreach($this->searchables as $qNumber => $searchable){
$qb[$qNumber] = "SELECT s FROM $searchable s ";
$columns = $this->em->getClassMetadata($searchable)->getColumnNames();
foreach($words as $i => $word){
foreach($columns as $k => $column){
$string = "s.$column LIKE '%$word%'";
if($i == 0 && $k == 0){
$qb[$qNumber] .= "WHERE $string";
} else {
$qb[$qNumber] .= "OR $string";
}
}
}
$res[] = $this->em->createQuery($qb[$qNumber])->getResult(Query::HYDRATE_SIMPLEOBJECT);
}
return $this->formatSearch($res);
}
private function formatSearch($results){
$formatedResult = array();
foreach($results as $k => $result){
if(!empty($result)){
$formatedResult[$k]["type"] = get_class($result[0]);
$formatedResult[$k]["data"] = $result[0];
}
}
return $formatedResult;
}
}
And my Controller for the search :
/**
* #Route("/search/{query}")
* #Template()
*/
public function indexAction($query)
{
$em = $this->getDoctrine()->getManager();
$searchables = new ArrayCollection(
array(
"SoundmergerUserBundle:Professional",
"SoundmergerFaqBundle:Faq",
"SoundmergerUserBundle:User",
));
$search = new Search($em, $searchables);
return array('search' => $search->search($query));
}
And finally my user entity :
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
* #AttributeOverrides({
* #AttributeOverride(name="emailCanonical",
* column=#ORM\Column(
* name = "emailCanonical",
* type = "string",
* length = 255,
* nullable = true
* )
* ),
* #AttributeOverride(name="email",
* column=#ORM\Column(
* name = "email",
* type = "string",
* length = 255,
* nullable = true
* )
* ),
* #AttributeOverride(name="username",
* column=#ORM\Column(
* name = "username",
* type = "string",
* length = 255,
* unique = false
* )
* ),
* #AttributeOverride(name="usernameCanonical",
* column=#ORM\Column(
* name = "usernameCanonical",
* type = "string",
* length = 255,
* unique = false
* )
* ),
* })
*/
class User extends BaseUser
{
const STRUCTURE_SOLO = "solo";
const STRUCTURE_GROUP = "group";
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\Column(type="string", nullable=true)
* #var string
*/
protected $nomProfile = null;
/**
* #ORM\Column(type="text", nullable=true)
* #var string
*/
protected $description = null;
/**
* #ORM\Column(type="string", nullable=true)
* #var string
*/
protected $type = null;
/**
* #ORM\Column(type="string")
* #var string
*/
protected $structure = self::STRUCTURE_SOLO;
/**
* #ORM\Column(type="string", nullable=true)
* #var string
*/
protected $tel = null;
/**
* #ORM\Column(type="string", nullable=true)
* #var string
*/
protected $site = null;
/**
* #ORM\Column(type="boolean")
* #var bool
*/
protected $firstLogin = true;
/**
* #ORM\OneToOne(targetEntity="Soundmerger\MainBundle\Entity\Address", cascade={"persist"})
*/
protected $address;
/**
* #ORM\OneToMany(targetEntity="Soundmerger\MainBundle\Entity\Style", mappedBy="user", cascade={"persist"})
*/
protected $styles;
/**
* #ORM\OneToMany(targetEntity="Soundmerger\UserBundle\Entity\Member", mappedBy="user")
* #ORM\JoinColumn(nullable=true)
*/
protected $members;
/** #ORM\Column(name="discogs_id", type="string", length=255, nullable=true) */
protected $discogs_id;
/** #ORM\Column(name="discogs_access_token", type="string", length=255, nullable=true) */
protected $discogs_access_token;
public function __construct()
{
parent::__construct();
$this->members = new ArrayCollection();
$this->styles = new ArrayCollection();
}
/**
* Get id
* #return string
*/
public function getId()
{
return $this->id;
}
/**
* Get NomProfile
* #return string
*/
public function getNomProfile()
{
return $this->nomProfile;
}
/**
* Get type
* #return string
*/
public function getType()
{
return $this->type;
}
/**
* Get structure
* #return string
*/
public function getStructure()
{
return $this->structure;
}
/**
* Get tel
* #return string
*/
public function getTel()
{
return $this->tel;
}
/**
* Get site
* #return string
*/
public function getSite()
{
return $this->site;
}
/**
* Get description
* #return string
*/
public function getDescription()
{
return $this->description;
}
/**
* Set nomProfile
* #param string $nomProfile
* #return \Soundmerger\UserBundle\Entity\Utilisateur
*/
public function setNomProfile($nomProfile)
{
$this->nomProfile = $nomProfile;
return $this;
}
/**
* Set type
* #param string $type
* #return \Soundmerger\UserBundle\Entity\Utilisateur
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* Set structure
* #param string $structure
* #return \Soundmerger\UserBundle\Entity\Utilisateur
*/
public function setStructure($structure)
{
if (!in_array($structure, array(self::STRUCTURE_SOLO, self::STRUCTURE_GROUP))) {
throw new \InvalidArgumentException("Invalid structure");
}
$this->structure = $structure;
return $this;
}
/**
* Set tel
* #param string $tel
* #return \Soundmerger\UserBundle\Entity\Utilisateur
*/
public function setTel($tel)
{
$this->tel = $tel;
return $this;
}
/**
* Set site
* #param string $site
* #return \Soundmerger\UserBundle\Entity\Utilisateur
*/
public function setSite($site)
{
$this->site = $site;
return $this;
}
/**
* Set description
* #param type $description
* #return \Soundmerger\UserBundle\Entity\Utilisateur
*/
public function setDescription($description)
{
$this->description = $description;
return $this;
}
/**
* Set the first login
* #param bool $firstLogin
* #return \Soundmerger\UserBundle\Entity\Utilisateur
*/
public function setFirstLogin($firstLogin)
{
$this->firstLogin = $firstLogin;
return $this;
}
/**
* Is it the first login
* #return bool returns true if its the first login, false otherwise
*/
public function isFirstLogin()
{
return $this->firstLogin;
}
/**
* Set address
*
* #param Address $address
* #return $this
*/
public function setAddress(Address $address)
{
$this->address = $address;
return $this;
}
/**
* Get adress
*
* #return mixed
*/
public function getAddress()
{
return $this->address;
}
/**
* #return Style
*/
public function getStyles()
{
return $this->styles;
}
/**
* #param Style $style
* #return $this
*/
public function addStyle(Style $style)
{
if (!$this->styles->contains($style)) {
$style->setUser($this);
$this->styles->add($style);
}
return $this;
}
public function setStyles(PersistentCollection $styles)
{
foreach ($styles as $style) {
$this->addStyle($style);
}
}
/**
* #return ArrayCollection
*/
public function getMembers()
{
return $this->members;
}
/**
* #param Member $members
*/
public function addMember(Member $member)
{
if (!$this->members->contains($member)) {
$this->members->add($member);
}
return $this;
}
public function setDiscogsId($discogs_id)
{
$this->discogs_id = $discogs_id;
return $this;
}
public function getDiscogsId()
{
return $this->discogs_id;
}
public function setDiscogsAccessToken($discogs_access_token)
{
$this->discogs_access_token = $discogs_access_token;
return $this;
}
public function getDiscogsAccessToken()
{
return $this->discogs_access_token;
}
public function isRegisteredWithDiscogs(){
return $this->discogs_id != null;
}
}
Any ideas on why this is only happening with the user entity (it must be due to the inheritance but i can't seem to find a way round it)
btw : its a university project so the idea of using an external bundle for the search is not really possible.
Thanks for any help
Dan
I've a problem with 'HasLifecycleCallbacks'. When I try to update only my image in my entity it's doesn't work (It doesn't display form error or php error). But if I update my image and a field (title or text) it's working !
There are no others bugs, all work except this feature.
namespace Acme\NewsBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Validator\Constraints as Assert;
/**
* News
*
* #ORM\Table(name="news")
* #ORM\HasLifecycleCallbacks
* #ORM\Entity(repositoryClass="Acme\NewsBundle\Entity\NewsRepository")
*/
class News
{
/**
* #var integer
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var string
*
* #ORM\Column(name="title", type="string", length=255)
*/
private $title;
/**
* #Gedmo\Slug(fields={"title"})
* #ORM\Column(length=255, unique=true)
*/
private $slug;
/**
* #var string
*
* #ORM\Column(name="image", type="string", length=255, nullable=true)
*/
private $image;
/**
* #Assert\File(maxSize="6000000")
*/
private $file;
private $oldFile;
/**
* #var string
*
* #ORM\Column(name="text", type="text")
*/
private $text;
/**
* #var \DateTime
*
* #ORM\Column(name="created", type="datetime")
*/
private $created;
public function __construct()
{
$this->created = new \Datetime;
}
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set title
*
* #param string $title
* #return News
*/
public function setTitle($title)
{
$this->title = $title;
return $this;
}
/**
* Get title
*
* #return string
*/
public function getTitle()
{
return $this->title;
}
/**
* Set slug
*
* #param string $slug
* #return News
*/
public function setSlug($slug)
{
$this->slug = $slug;
return $this;
}
/**
* Get slug
*
* #return string
*/
public function getSlug()
{
return $this->slug;
}
/**
* Set image
*
* #param string $image
* #return News
*/
public function setImage($image)
{
$this->image = $image;
return $this;
}
/**
* Get image
*
* #return string
*/
public function getImage()
{
return $this->image;
}
/**
* Set file
*
* #param string $file
* #return News
*/
public function setFile($file)
{
$this->file = $file;
return $this;
}
/**
* Get file
*
* #return string
*/
public function getFile()
{
return $this->file;
}
/**
* Set text
*
* #param string $text
* #return News
*/
public function setText($text)
{
$this->text = $text;
return $this;
}
/**
* Get text
*
* #return string
*/
public function getText()
{
return $this->text;
}
/**
* Set created
*
* #param \DateTime $created
* #return News
*/
public function setCreated($created)
{
$this->created = $created;
return $this;
}
/**
* Get created
*
* #return \DateTime
*/
public function getCreated()
{
return $this->created;
}
// upload img
public function getFullFilePath()
{
return null === $this->file ? null : $this->getUploadRootDir(). $this->file;
}
public function getUploadRootDir()
{
// the absolute directory path where uploaded documents should be saved
return $this->getTmpUploadRootDir()."news/";
}
protected function getTmpUploadRootDir()
{
// the absolute directory path where uploaded documents should be saved
return __DIR__ . '/../../../../web/up/';
}
public function getFilePath()
{
return null === $this->file ? null : "/web/up/news/". $this->file;
}
/**
* #ORM\PreUpdate()
*/
public function delOldFile()
{
if (null === $this->file) {
return;
}
if(file_exists($this->getUploadRootDir().$this->image)){
$oldDir = $this->getUploadRootDir().$this->image;
if(file_exists($oldDir)) {
unlink($oldDir);
}
}
}
/**
* #ORM\PrePersist()
* #ORM\PreUpdate()
*/
public function uploadFile()
{
var_dump(true); die();
// the file property can be empty if the field is not required
if (null === $this->file) {
return;
}
if(!is_dir($this->getUploadRootDir())){
mkdir($this->getUploadRootDir());
}
$extension = pathinfo($this->file->getClientOriginalName(), PATHINFO_EXTENSION);
$name = uniqid().'.'.$extension;
$this->file->move($this->getUploadRootDir().'/', $name);
// resize 145*145
$cropImg = $this->getUploadRootDir().'/'.$name;
$cropDest = $this->getUploadRootDir().'/'.$name;
$largeur = 145;
$hauteur = 145;
$dimension = getimagesize($cropImg);
$ratio = $dimension[0] / $dimension[1];
if($largeur == 0 && $hauteur == 0){ $largeur = $dimension[0]; $hauteur = $dimension[1]; }
else if($hauteur == 0){ $hauteur = round($largeur / $ratio); }
else if($largeur == 0){ $largeur = round($hauteur * $ratio); }
if($dimension[0] > ($largeur/$hauteur)*$dimension[1] ){ $dimY = $hauteur; $dimX = round($hauteur*$dimension[0]/$dimension[1]); $decalX=($dimX-$largeur)/2; $decalY=0;}
if($dimension[0] < ($largeur/$hauteur)*$dimension[1]){ $dimX = $largeur; $dimY = round($largeur*$dimension[1]/$dimension[0]); $decalY=($dimY-$hauteur)/2; $decalX=0;}
if($dimension[0] == ($largeur/$hauteur)*$dimension[1]){ $dimX = $largeur; $dimY = $hauteur; $decalX=0; $decalY=0;}
$miniature = imagecreatetruecolor ($largeur,$hauteur);
if(in_array($extension,array('jpeg','jpg','JPG','JPEG'))){$file = imagecreatefromjpeg($cropImg); }
elseif(in_array($extension,array('png','PNG'))){$file = imagecreatefrompng($cropImg); }
elseif(in_array($extension,array('gif','GIF'))){$file = imagecreatefromgif($cropImg); }
else{ return false; }
imagecopyresampled($miniature,$file,-$decalX,-$decalY,0,0,$dimX,$dimY,$dimension[0],$dimension[1]);
imagejpeg($miniature,$cropDest,90);
$this->setImage($name);
}
/**
* #ORM\PostPersist()
*/
public function moveFile()
{
if (null === $this->file) {
return;
}
if(!is_dir($this->getUploadRootDir())){
mkdir($this->getUploadRootDir());
}
}
/**
* #ORM\PreRemove()
*/
public function removeFile()
{
if ($this->getFullFilePath()) {
unlink($this->getFullFilePath());
}
}
}
This issue is a known bug, check out the doc: http://symfony.com/doc/current/cookbook/doctrine/file_uploads.html#using-lifecycle-callbacks
To resolve this, the doc suggest you to use a "updatedAt" field that will be updated each time you persist your entity, even if only the file field changed.
Check that your entity form type has a mapped (mapped option set to true) image field.,
$builder->add('createdDateTime',null,
array("mapped" => true,
"required" => false,
"description" => "Thedatetime of creation")
);
I've generated the form through entity generator,
I've extended the Cobrand Controller
class CobrandController extends Controller
{
public function createAction()
{
// the key used to lookup the template
$templateKey = 'edit';
if (false === $this->admin->isGranted('CREATE')) {
throw new AccessDeniedException();
}
$object = $this->admin->getNewInstance();
$this->admin->setSubject($object);
/** #var $form \Symfony\Component\Form\Form */
$form = $this->admin->getForm();
$form->setData($object);
if ($this->getRestMethod()== 'POST') {
// $cobrand = new Cobrand();
$em=$this->getDoctrine()->getManager();
$cobrand=new Cobrand($em);
$form->bind($this->get('request'));
$isFormValid = $form->isValid();
// persist if the form was valid and if in preview mode the preview was approved
if ($isFormValid && (!$this->isInPreviewMode() || $this->isPreviewApproved())) {
$this->admin->create($object);
if ($this->isXmlHttpRequest()) {
return $this->renderJson(array(
'result' => 'ok',
'objectId' => $this->admin->getNormalizedIdentifier($object)
));
}
$this->addFlash('sonata_flash_success','flash_create_success');
// redirect to edit mode
return $this->redirectTo($object);
}
// show an error message if the form failed validation
if (!$isFormValid) {
if (!$this->isXmlHttpRequest()) {
$this->addFlash('sonata_flash_error', 'flash_create_error');
}
} elseif ($this->isPreviewRequested()) {
// pick the preview template if the form was valid and preview was requested
$templateKey = 'preview';
$this->admin->getShow();
}
}
$view = $form->createView();
// set the theme for the current Admin Form
$this->get('twig')->getExtension('form')->renderer->setTheme($view, $this->admin->getFormTheme());
return $this->render($this->admin->getTemplate($templateKey), array(
'action' => 'create',
'form' => $view,
'object' => $object,
));
}
}
Here's my entity code,
class Cobrand
{
/**
* #var \DateTime
*/
private $created;
/**
* #var \DateTime
*/
private $updated;
/**
* #var string
*/
private $name;
/**
* #var string
*/
private $code;
/**
* #var string
*/
private $logo;
/**
* #var boolean
*/
private $cobrandedProductsOnly;
/**
* #var integer
*/
private $id;
/**
* #var \Doctrine\Common\Collections\Collection
*/
private $productPrices;
/**
* #var \Doctrine\Common\Collections\Collection
*/
private $promocodes;
/**
* Constructor
*/
public function __construct()
{
$this->productPrices = new \Doctrine\Common\Collections\ArrayCollection();
$this->promocodes = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Set created
*
* #param \DateTime $created
* #return Cobrand
*/
public function setCreated($created)
{
$this->created = $created;
return $this;
}
/**
* Get created
*
* #return \DateTime
*/
public function getCreated()
{
return $this->created;
}
/**
* Set updated
*
* #param \DateTime $updated
* #return Cobrand
*/
public function setUpdated($updated)
{
$this->updated = $updated;
return $this;
}
/**
* Get updated
*
* #return \DateTime
*/
public function getUpdated()
{
return $this->updated;
}
/**
* Set name
*
* #param string $name
* #return Cobrand
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* #return string
*/
public function getName()
{
return $this->name;
}
/**
* Set code
*
* #param string $code
* #return Cobrand
*/
public function setCode($code)
{
$this->code = $code;
return $this;
}
/**
* Get code
*
* #return string
*/
public function getCode()
{
return $this->code;
}
}
User will enter the values on the form and I wan't to access those values in the createAction method of controller.
I want to change the value of $name in the controller.
How to access this ?
Thanks,
Faisal Nasir
Try this after binding request
$form->get('name')->setData('new value');
I have this entity (Registro):
<?php
namespace Gitek\RegistroBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Gitek\RegistroBundle\Entity\Registro
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="Gitek\RegistroBundle\Entity\RegistroRepository"))
*/
class Registro
{
/**
* #var integer $id
*
* #ORM\Column(name="id", type="integer")
* #ORM\Id
* #ORM\GeneratedValue(strategy="AUTO")
*/
private $id;
/**
* #var datetime $fecha
*
* #ORM\Column(name="fecha", type="datetime")
*/
private $fecha;
/**
* #var smallint $comenzado
*
* #ORM\Column(name="comenzado", type="smallint", nullable=true)
*/
private $comenzado;
/**
* #var smallint $completado
*
* #ORM\Column(name="completado", type="smallint", nullable=true)
*/
private $completado;
/**
* #var datetime $created_at
*
* #ORM\Column(name="created_at", type="datetime")
*/
private $created_at;
/**
* #var datetime $updated_at
*
* #ORM\Column(name="updated_at", type="datetime")
*/
private $updated_at;
/** #ORM\ManyToOne(targetEntity="Gitek\UsuarioBundle\Entity\Usuario") */
protected $usuario;
/** #ORM\ManyToOne(targetEntity="Gitek\HotelBundle\Entity\Tipotarea") */
protected $tipotarea;
/** #ORM\ManyToOne(targetEntity="Gitek\HotelBundle\Entity\Habitacion") */
protected $habitacion;
/** #ORM\ManyToOne(targetEntity="Gitek\RegistroBundle\Entity\Master") */
protected $master;
/**
* #ORM\ManyToMany(targetEntity="Gitek\HotelBundle\Entity\Incidencia", inversedBy="registros")
* #ORM\JoinTable(name="incidencia_registro",
* joinColumns={#ORM\JoinColumn(name="registro_id", referencedColumnName="id")},
* inverseJoinColumns={#ORM\JoinColumn(name="incidencia_id", referencedColumnName="id")}
* )
*/
protected $incidencias;
public function __construct()
{
$this->created_at = new \DateTime();
$this->updated_at = new \DateTime();
}
// public function __toString()
// {
// return $this->getNombre();
// }
/**
* Get id
*
* #return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set fecha
*
* #param datetime $fecha
*/
public function setFecha($fecha)
{
$this->fecha = $fecha;
}
/**
* Get fecha
*
* #return datetime
*/
public function getFecha()
{
return $this->fecha;
}
/**
* Set comenzado
*
* #param smallint $comenzado
*/
public function setComenzado($comenzado)
{
$this->comenzado = $comenzado;
}
/**
* Get comenzado
*
* #return smallint
*/
public function getComenzado()
{
return $this->comenzado;
}
/**
* Set completado
*
* #param smallint $completado
*/
public function setCompletado($completado)
{
$this->completado = $completado;
}
/**
* Get completado
*
* #return smallint
*/
public function getCompletado()
{
return $this->completado;
}
/**
* Set created_at
*
* #param datetime $createdAt
*/
public function setCreatedAt($createdAt)
{
$this->created_at = $createdAt;
}
/**
* Get created_at
*
* #return datetime
*/
public function getCreatedAt()
{
return $this->created_at;
}
/**
* Set updated_at
*
* #param datetime $updatedAt
*/
public function setUpdatedAt($updatedAt)
{
$this->updated_at = $updatedAt;
}
/**
* Get updated_at
*
* #return datetime
*/
public function getUpdatedAt()
{
return $this->updated_at;
}
/**
* Set usuario
*
* #param Gitek\UsuarioBundle\Entity\Usuario $usuario
*/
public function setUsuario(\Gitek\UsuarioBundle\Entity\Usuario $usuario)
{
$this->usuario = $usuario;
}
/**
* Get usuario
*
* #return Gitek\UsuarioBundle\Entity\Usuario
*/
public function getUsuario()
{
return $this->usuario;
}
/**
* Set tipotarea
*
* #param Gitek\HotelBundle\Entity\Tipotarea $tipotarea
*/
public function setTipotarea(\Gitek\HotelBundle\Entity\Tipotarea $tipotarea)
{
$this->tipotarea = $tipotarea;
}
/**
* Get tipotarea
*
* #return Gitek\HotelBundle\Entity\Tipotarea
*/
public function getTipotarea()
{
return $this->tipotarea;
}
/**
* Set habitacion
*
* #param Gitek\HotelBundle\Entity\Habitacion $habitacion
*/
public function setHabitacion(\Gitek\HotelBundle\Entity\Habitacion $habitacion)
{
$this->habitacion = $habitacion;
}
/**
* Get habitacion
*
* #return Gitek\HotelBundle\Entity\Habitacion
*/
public function getHabitacion()
{
return $this->habitacion;
}
/**
* Add incidencias
*
* #param Gitek\HotelBundle\Entity\Incidencia $incidencias
*/
public function addIncidencia(\Gitek\HotelBundle\Entity\Incidencia $incidencias)
{
$this->incidencias[] = $incidencias;
}
/**
* Get incidencias
*
* #return Doctrine\Common\Collections\Collection
*/
public function getIncidencias()
{
return $this->incidencias;
}
}
I wanted to save multiple data on a row, so I created a new Entity with only an array propery like this (Master):
<?php
namespace Gitek\RegistroBundle\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
class Master
{
/** #ORM\OneToMany(targetEntity="Gitek\HotelBundle\Entity\Habitacion", mappedBy="master") */
protected $registros;
public function __construct()
{
$this->registros = new ArrayCollection();
}
public function getRegistros()
{
return $this->registros;
}
public function setRegistros(ArrayCollection $registros)
{
$this->registros = $registros;
}
}
I created my MasterType like this:
<?php
namespace Gitek\RegistroBundle\Form;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilder;
use Doctrine\ORM\EntityRepository;
class MasterType extends AbstractType
{
public function buildForm(FormBuilder $builder, array $options)
{
$builder
->add('registros', 'collection', array(
'type' => new RegistroType(),
'allow_add' => true,
'by_reference' => true,
));
}
public function getDefaultOptions(array $options)
{
return array(
'data_class' => 'Gitek\RegistroBundle\Entity\Master'
);
}
public function getName()
{
return 'master';
}
}
And this is my controller:
public function asignarAction()
{
$master = new Master();
$request = $this->getRequest();
$form = $this->createForm(new MasterType(), $master);
if ('POST' === $request->getMethod()) {
$form->bindRequest($request);
if ($form->isValid()) {
$em = $this->getDoctrine()->getEntityManager();
$em->persist($master);
$em->flush();
return $this->redirect($this->generateUrl('recepcion_asignar'));
}else {
print_r("ezez");
print_r($form->getErrors());
}
} else {
}
return $this->render('RegistroBundle:Recepcion:asignar.html.twig', array(
'registro' => $master,
'form' => $form->createView()
));
}
The form works ok, and I see the data is submited correctly but it is not persisted, I´m getting this error all the time:
Class Gitek\RegistroBundle\Entity\Master is not a valid entity or mapped super class.
I think that the problem is within de Master entity.
Any help or clue?
You missed the #Entity annotation on your Master class, you will also need a master table on your database for this to work.
If you don't want to create the master table, then you can skip the #Entity annotation, but you can not persist master. Instead you would have to iterate through the collection and persist only the entities in the array.