Search code examples
symfonydoctrine-ormsymfony-formsdoctrine-mapping

Expected value of type for association field , got "double" instead


I want to put a number into a NumberType field, but when I get this exception:

Expected value of type "GestionBundle\Entity\MaterialCost" for association field "GestionBundle\Entity\Intervention#$materialCost", got "double" instead.

Intervention

namespace GestionBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\Mapping\OneToOne;

/**
 * @ORM\Entity
 */
class Intervention
{
    /**
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="comments", type="text", nullable=true)
     */
    private $comments;

    /**
     * One Intervention has One materialCost.
     * @OneToOne(targetEntity="MaterialCost", inversedBy="intervention", cascade={"persist"}) 
     */
    private $materialCost;

    public function __toString() {
        if (is_null($this->comments)) {
            return '';
        }
        return $this->comments;
    }
}

MaterialCost

namespace GestionBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 */
class MaterialCost
{
    /*
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @var float
     * @ORM\Column(name="material_cost", type="float")
     */
    private $materialCost;

    /**
     * @ORM\OneToOne(targetEntity="Intervention", mappedBy="materialCost") 
     */
    private $intervention;

    public function __toString() {
        return (string) $this->materialCost;  
    }
}

InterventionType

namespace GestionBundle\Form;

use Doctrine\ORM\EntityRepository;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\TextareaType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class InterventionType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
        $builder->add('materialCost',  NumberType::class, ['required' => true])
                ->add('comments', TextareaType::class, ['required' => false])
        ;
    }

    public function configureOptions(OptionsResolver $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'GestionBundle\Entity\MaterialCost'
        ));
    }
}

Solution

  • That is clear you should pass an object to the materialCost property of Intervention entity object, but you are giving it a number instead, which is wrong.

    I think you'd better throw away the MaterialCost entity class totally and change Intervention's materialCost property mapping like this:

    Intervention

    /**
     * Intervention has a materialCost value.
     * @ORM/Column(type="float", name="material_cost") 
     */
    private $materialCost;
    

    But if you are sure about having that MaterialCost entity class in place, this is the way to go:

    InterventionType

    namespace GestionBundle\Form;
    
    use Doctrine\ORM\EntityRepository;
    use GestionBundle\Entity\Intervention;
    use GestionBundle\Entity\MaterialCost;
    use Symfony\Bridge\Doctrine\Form\Type\EntityType;
    use Symfony\Component\Form\AbstractType;
    use Symfony\Component\Form\Extension\Core\Type\TextareaType;
    use Symfony\Component\Form\FormBuilderInterface;
    use Symfony\Component\OptionsResolver\OptionsResolver;
    
    class InterventionType extends AbstractType
    {
        public function buildForm(FormBuilderInterface $builder, array $options)
        {
            $builder
                ->add('materialCost',  EntityType::class, [
                    'required' => true,
                    'class' => MaterialCost::class,
                    'choice_label' => 'materialCost',
                    ])
                ->add('comments', TextareaType::class, ['required' => false])
            ;
        }
    
        public function configureOptions(OptionsResolver $resolver)
        {
            $resolver->setDefaults(array(
                'data_class' => Intervention::class
            ));
        }
    }
    

    This way, you may choose some instance of MaterialCost and assing it to an Intervention. If you want to be able to put a new number, and at the same time, create a MaterialCost object, inside InterventionType form, you are after an other method called prototype.

    Consider reading the How to Embed a Collection of Forms for that.