Skip to content

Form Collection #9973

@pdias

Description

@pdias

Hello,

I'm using a a2lix/TranslationsForm, with this entities:

namespace Catalogue\OptionBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;

use Catalogue\OptionBundle\Entity\OptionValue;

/**
 * @ORM\Table(name="option_", options={"comment":"Criado por Paulo Dias"})
 * @ORM\Entity(repositoryClass="Catalogue\OptionBundle\Repository\OptionRepository")
  */
class Option
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue
     */
    private $id;

    /**
     * @Gedmo\Translatable
     * @ORM\Column(length=200)
     */
    private $name;

    /**
     * @Gedmo\Translatable
     * @ORM\Column(type="text", nullable=false)
     */
    private $presentation;

    /** 
     * @ORM\OneToMany(targetEntity="Catalogue\OptionBundle\Entity\OptionValue", mappedBy="option", cascade={"all"})
     */
    private $optionvalues;

    /**
     * @Gedmo\Timestampable(on="create")
     * @ORM\Column(type="datetime")
     */
    private $created;

    /**
     * @Gedmo\Timestampable(on="update")
     * @ORM\Column(type="datetime")
     */
    private $updated;

    /**
     * @ORM\OneToMany(
     *   targetEntity="OptionTranslation",
     *   mappedBy="object",
     *   indexBy="locale",
     *   cascade={"all"}
     * )
     */
    private $translations;

    public function __construct()
    {
        $this->translations = new ArrayCollection();
        $this->optionvalues = new ArrayCollection();
        $this->created = new \DateTime();
    }

    /**
     * Get id
     *
     * @return Integer
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param String $name
     */
    public function setName($name)
    {
        $this->name = $name;
        return $this;
    }

    /**
     * Get name
     *
     * @return String
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set presentation
     *
     * @param String $presentation
     */
    public function setPresentation($presentation)
    {
        $this->presentation = $presentation;
        return $this;
    }

    /**
     * Get presentation
     *
     * @return String
     */
    public function getPresentation()
    {
        return $this->presentation;
    }

    /**
     * Set values
     *
     * @param Doctrine\Common\Collections\Collection $values
     */
    /*public function setValues(Collection $values)
    {
        $this->values = $values;
        return $this;
    }*/

    /**
     * Get options values
     *
     * @return Doctrine\Common\Collections\Collection
     */
    public function getOptionValues()
    {
        return $this->optionvalues;
    }

    /**
     * Add option value
     *
     * @param Catalogue\OptionBundle\Entity\OptionValue $optionvalue
     */
    public function addOptionValue(OptionValue $optionvalue)
    {
        if(!$this->hasValue($optionvalue)) {
            $optionvalue->setOption($this);
            $this->optionvalues->add($optionvalue);
        }

        return $this;
    }

    /**
     * Remove option value
     * 
     * @param Catalogue\OptionBundle\Entity\OptionValue $optionvalue
     */
    public function removeOptionValue(OptionValue $optionvalue)
    {
        if ($this->optionvalues->contains($optionvalue)) {
            $this->optionvalues->removeElement($optionvalue);
        }
    }

    /**
     * Option have value 
     */
    public function hasValue(OptionValue $optionvalue)
    {
        return $this->optionvalues->contains($optionvalue);
    }

    /**
     * Get created
     *
     * @return DateTime
     */
    public function getCreated()
    {
        return $this->created;
    }

    /**
     * Get updated
     *
     * @return DateTime
     */
    public function getUpdated()
    {
        return $this->updated;
    }

    /**
     * Get translations
     *
     * @return Doctrine\Common\Collections\Collection
     */
    public function getTranslations()
    {
        return $this->translations;
    }

    /**
     * Add translation
     *
     * @param Catalogue\OptionBundle\Entity\OptionTranslation $t
     */
    public function addTranslation(OptionTranslation $t)
    {
        if (!$this->translations->contains($t)) {
            $t->setObject($this);
            $this->translations->set($t->getLocale(), $t);
        }
    }

    /**
     * Remove translation
     * 
     * @param Catalogue\OptionBundle\Entity\OptionTranslation $t
     */
    public function removeTranslation(OptionTranslation $t)
    {
        if ($this->translations->contains($t)) {
            $this->translations->removeElement($t);
        }
    }

    public function __toString()
    {
        return $this->getPresentation();
    }
}
namespace Catalogue\OptionBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Translatable\Entity\MappedSuperclass\AbstractTranslation;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity
 * @ORM\Table(uniqueConstraints={
 *   @ORM\UniqueConstraint(name="option_translation_unique_idx", columns={"locale", "object_id"})
 * }, options={"comment":"Criado por Paulo Dias"})
 */
class OptionTranslation extends AbstractTranslation
{
    /**
     * @ORM\ManyToOne(targetEntity="Option", inversedBy="translations")
     * @ORM\JoinColumn(name="object_id", referencedColumnName="id", onDelete="CASCADE", nullable=false)
     */
    protected $object;

    /**
     * @ORM\Column(length=200)
     * @Assert\NotBlank(message = "option.name.not_blank")
     */
    private $name;

    /**
     * @ORM\Column(type="text", nullable=false)
     * @Assert\NotBlank(message = "option.presentation.not_blank")
     */
    private $presentation;

    /**
     * Convinient constructor
     *
     * @param string $locale
     * @param string $name
     * @param string $presentation
     */
    public function __construct($locale = null, $name = null, $presentation = null)
    {
        $this->locale = $locale;
        $this->name = $name;
        $this->presentation = $presentation;
    }

    public function setName($name)
    {
        $this->name = $name;
        return $this;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setPresentation($presentation)
    {
        $this->presentation = $presentation;
        return $this;
    }

    public function getPresentation()
    {
        return $this->presentation;
    }
}
namespace Catalogue\OptionBundle\Entity;

use Doctrine\Common\Collections\ArrayCollection;
use Gedmo\Mapping\Annotation as Gedmo;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;

use Catalogue\OptionBundle\Entity\Option;
use Catalogue\OptionBundle\Entity\OptionValueTranslation;

/**
 * @ORM\Table(name="optionvalue", options={"comment":"Criado por Paulo Dias"})
 * @ORM\Entity(repositoryClass="Catalogue\OptionBundle\Repository\OptionRepository")
  */
class OptionValue
{
    /**
     * @ORM\Column(type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue
     */
    private $id;

    /** 
     * @Assert\NotNull(message = "optionvalue.option.not_null")
     * @ORM\ManyToOne(targetEntity="Catalogue\OptionBundle\Entity\Option", inversedBy="optionvalues")
     * @ORM\JoinColumn(name="option", referencedColumnName="id")
     */
    private $option;

    /**
     * @Gedmo\Translatable
     * @ORM\Column(type="text", nullable=false)
     */
    private $value;

     /**
     * @ORM\OneToMany(
     *   targetEntity="OptionValueTranslation",
     *   mappedBy="object",
     *   indexBy="locale",
     *   cascade={"all"}
     * )
     */
    private $translations;

    public function __construct()
    {
        $this->translations = new ArrayCollection();
    }

    public function getId()
    {
        return $this->id;
    }

    /**
     * Set option
     *
     * @param Catalogue\OptionBundle\Entity\Option $option
     */
    public function setOption(Option $option = null)
    {
        $this->option = $option;
        return $this;
    }

    /**
     * Get option
     *
     * @return Catalogue\OptionBundle\Entity\Option
     */
    public function getOption()
    {
        return $this->option;
    }

    /**
     * Set value
     *
     * @param String $value
     */
    public function setValue($value)
    {
        $this->value = $value;
        return $this;
    }

    /**
     * Get value
     *
     * @return string
     */
    public function getValue()
    {
        return $this->value;
    }

    /**
     * Get option name
     *
     * @return string
     */
    public function getName()
    {
        if (null === $this->option) {
            throw new \BadMethodCallException('The option have not been created yet so you cannot access proxy methods.');
        }

        return $this->option->getName();
    }

    /**
     * Get voption presentation
     *
     * @return string
     */
    public function getPresentation()
    {
        if (null === $this->option) {
            throw new \BadMethodCallException('The option have not been created yet so you cannot access proxy methods.');
        }
        return $this->option->getPresentation();
    }

    /**
     * Get translations
     *
     * @return Doctrine\Common\Collections\Collection
     */
    public function getTranslations()
    {
        return $this->translations;
    }

    /**
     * Add translation
     *
     * @param Catalogue\OptionBundle\Entity\OptionValueTranslation $t
     */
    public function addTranslations(OptionValueTranslation $t)
    {
        if (!$this->translations->contains($t)) {
            $t->setObject($this);
            $this->translations->set($t->getLocale(), $t);
        }
    }

    /**
     * Remove translation
     * 
     * @param Catalogue\OptionBundle\Entity\OptionValueTranslation $t
     */
    public function removeTranslations(OptionValueTranslation $t)
    {
        if ($this->translations->contains($t)) {
            $this->translations->removeElement($t);
        }
    }
}
namespace Catalogue\OptionBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Gedmo\Translatable\Entity\MappedSuperclass\AbstractTranslation;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * @ORM\Entity
 * @ORM\Table(uniqueConstraints={
 *   @ORM\UniqueConstraint(name="optionvalue_translation_unique_idx", columns={"locale", "object_id"})
 * }, options={"comment":"Criado por Paulo Dias"})
 */
class OptionValueTranslation extends AbstractTranslation
{
    /**
     * @ORM\ManyToOne(targetEntity="OptionValue", inversedBy="translations")
     * @ORM\JoinColumn(name="object_id", referencedColumnName="id", onDelete="CASCADE", nullable=false)
     */
    protected $object;

    /**
     * @Assert\NotBlank(message = "optionvalue.value.not_blank")
     * @ORM\Column(type="text", nullable=false)
     */
    private $value;

    /**
     * Convinient constructor
     *
     * @param string $locale
     * @param string $value
     */
    public function __construct($locale = null, $value = null)
    {
        $this->locale = $locale;
        $this->value = $value;
    }

    public function setValue($value)
    {
        $this->value = $value;
        return $this;
    }

    public function getValue()
    {
        return $this->value;
    }
}

And I use this Form Types:

namespace Catalogue\OptionBundle\Form\Type;

use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;

class OptionValueType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add(
            'translations',
            'a2lix_translations',
            array(
                'attr'=>array('class'=>'form-control'),
                'label_attr'=>array('class' =>'sr-only'),
                'fields'=>array(
                    'value'=>array(
                        'field_type'=>'text',
                        'attr'=>array('class'=>'form-control'),
                    ),
                ),
             )
        );
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver
            ->setDefaults(array(
                'data_class'=>'Catalogue\OptionBundle\Entity\OptionValue',
              ));
    }

    public function getName()
    {
        return 'optionvalue';
    }
}
namespace Catalogue\OptionBundle\Form\Type;

use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;

use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormEvent;

class OptionType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add(
            'translations',
            'a2lix_translations',
            array(
                'attr'=>array('class'=>'form-control'),
                'label_attr'=>array('class' =>'sr-only'),
                'fields'=>array(
                    'name'=>array(
                        'field_type'=>'text',
                        'attr'=>array('class'=>'form-control'),
                    ),
                    'presentation'=>array(
                        'field_type'=>'text',
                        'attr'=>array('class'=>'form-control'),
                    ),
                ),
             )
        );

        $builder->add('optionvalues', 'collection', array(
            'type'=> new OptionValueType(),
            'by_reference'=>false,
            'allow_add'=>true,
            'allow_delete'=>true,
        ));

        $builder->add('save', 'submit', array('label'=>'Save', 'attr'=>array('class'=>'btn btn-cms btn-sm')));
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver
            ->setDefaults(array(
                'data_class'=>'Catalogue\OptionBundle\Entity\Option',
                'cascade_validation'=>true, //Necessário
              ));
    }

    public function getName()
    {
        return 'option';
    }
}

In the code of OptionType I have a collection of OptionValuesType.
If I not add any element (OptionValue) to collection and submit the form, everything is fine.
But if I add an element to the collection, gives me an error, which I think it is not in the bundleI a2lix.

An example of data submitted:

Form->submit(array(
    'translations' => array(
        'en' => array(
            'name' => 'My Option',
            'presentation' => 'Option'
        ), 
        'pt' => array(
            'name' => '',
            'presentation' => ''
        )
    ), 
    'optionvalues' => array(
        array(
            'translations' => array(
                'en' => array(
                    'value' => 'Red'
                ), 
                'pt' => array(
                    'value' => 'Vermelho'
                )
            )
        )
    ), 
    'save' => '', 
    '_token' => 'eCMv2xRfeJcd0pJj-J5I9zgSMV999_lxniJ2kgtGxQA'
), true)

And I have this error:

    in C:\EasyPHP\www\sym\src\Catalogue\OptionBundle\Entity\Option.php line 213
    at ErrorHandler->handle('4096', 'Argument 1 passed to Catalogue\OptionBundle\Entity\Option::addTranslation() must be an instance of Catalogue\OptionBundle\Entity\OptionTranslation, instance of Catalogue\OptionBundle\Entity\OptionValueTranslation given', 'C:\EasyPHP\www\sym\src\Catalogue\OptionBundle\Entity\Option.php', '213', array('this' => object(Option))) in C:\EasyPHP\www\sym\src\Catalogue\OptionBundle\Entity\Option.php line 213
    at Option->addTranslation(object(OptionValueTranslation))
    at call_user_func(array(object(Option), 'addTranslation'), object(OptionValueTranslation)) in C:\EasyPHP\www\sym\vendor\symfony\symfony\src\Symfony\Component\PropertyAccess\PropertyAccessor.php line 363
    at PropertyAccessor->writeProperty(object(Option), 'translations', null, object(ArrayCollection)) in C:\EasyPHP\www\sym\vendor\symfony\symfony\src\Symfony\Component\PropertyAccess\PropertyAccessor.php line 102
    at PropertyAccessor->setValue(object(Option), object(PropertyPath), object(ArrayCollection)) in C:\EasyPHP\www\sym\vendor\symfony\symfony\src\Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper.php line 87
    at PropertyPathMapper->mapFormsToData(object(RecursiveIteratorIterator), object(Option)) in C:\EasyPHP\www\sym\vendor\symfony\symfony\src\Symfony\Component\Form\Form.php line 616
    at Form->submit(array('translations' => array('en' => array('name' => 'My Option', 'presentation' => 'Option'), 'pt' => array('name' => '', 'presentation' => '')), 'optionvalues' => array(array('translations' => array('en' => array('value' => 'Red'), 'pt' => array('value' => 'Vermelho')))), 'save' => '', '_token' => 'eCMv2xRfeJcd0pJj-J5I9zgSMV999_lxniJ2kgtGxQA'), true) in C:\EasyPHP\www\sym\vendor\symfony\symfony\src\Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler.php line 80
    at HttpFoundationRequestHandler->handleRequest(object(Form), object(Request)) in C:\EasyPHP\www\sym\vendor\symfony\symfony\src\Symfony\Component\Form\Form.php line 488
    at Form->handleRequest(object(Request)) in C:\EasyPHP\www\sym\src\Catalogue\OptionBundle\Controller\OptionController.php line 59
    at OptionController->addAction('1', object(Request))
    at call_user_func_array(array(object(OptionController), 'addAction'), array('1', object(Request))) in C:\EasyPHP\www\sym\app\bootstrap.php.cache line 2911
    at HttpKernel->handleRaw(object(Request), '1') in C:\EasyPHP\www\sym\app\bootstrap.php.cache line 2883
    at HttpKernel->handle(object(Request), '1', true) in C:\EasyPHP\www\sym\app\bootstrap.php.cache line 3022
    at ContainerAwareHttpKernel->handle(object(Request), '1', true) in C:\EasyPHP\www\sym\app\bootstrap.php.cache line 2303
    at Kernel->handle(object(Request)) in C:\EasyPHP\www\sym\public_html\app_dev.php line 28

I do not know why, but this PropertyAccessor.php call my object Option with the parameter OptionValueTranslation, should call with OptionTranslation.

call_user_func(array(object(Option), 'addTranslation'), object(OptionValueTranslation)) in C:\EasyPHP\www\sym\vendor\symfony\symfony\src\Symfony\Component\PropertyAccess\PropertyAccessor.php line 363

I use Symfony2 2.4.1.

Thanks.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions