Search code examples
symfonydoctrinefixtures

ORMInvalidArgumentException when trying to set related objects in Doctrine fixtures


I'm new to Symfony and Doctrine. I have a few different entities that are related, but when I try to associate them in Fixtures I get an exception:

Expected value of type "App\Entity\VehicleType" for association field "App\Entity\Make#$type", got "Doctrine\Common\Collections\ArrayColl
ection" instead.

This seems to get thrown as soon as I call $manager->flush() in the second fixture. I used the entity generator to set these up and the relationships. Afterward I added JoinColumn to the ManyToOne annotations. These relationships are setup like this:

class VehicleType
{
    /** 
     * @ORM\OneToMany(targetEntity="App\Entity\Make", mappedBy="type")
     */
    private $make;

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

class make
{

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\VehicleType", inversedBy="make")
     * @ORM\JoinColumn(name="type", referencedColumnName="code")
     */
    private $type;

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

And the fixtures look like this:

class VehicleTypeFixtures extends Fixture
{
    public function load(ObjectManager $manager)
    {
        $vehicleTypesData = AppFixtures::loadJSON('vehicle_types.json');

        foreach($vehicleTypesData as $type) {
            $vehicleType = new VehicleType();
            $vehicleType->setCode($type->code);
            $vehicleType->setDescription($type->description);
            $manager->persist($vehicleType);
            $this->addReference('type-'.$type->code, $vehicleType);
        }

        $manager->flush();
    }
}

class MakeFixtures extends Fixture implements DependentFixtureInterface
{
    public function load(ObjectManager $manager)
    {
        $makes = AppFixtures::loadJSON('makes.json');

        foreach($makes as $make) {
            $newMake = new Make();
            $newMake->setCode($make->code);
            $newMake->setDescription($make->description);

            $type = (!empty($this->hasReference('type-'.$make->type)))
                ? $this->getReference('type-'.$make->type)
                : false;
            if ($type) {
                $newMake->setType($type);
            }

            $manager->persist($newMake);
        }

        $manager->flush();
    }
}

I see in the console they are definitely executing in the right order. Clearly I'm setting $this->make and $this->type to new ArrayCollection()s in the constructors, but that was added by the entity generator and it seems like what I want.

When I dump the get_class on the $type object in the Make fixture I see that it is a Proxies\__CG__\App\Entity\Type which should be right?

Edit: My schema looks like this:

vehicle_type:
| code        | varchar(10)  | NO   | PRI | NULL    |       |
| description | varchar(255) | NO   |     | NULL    |       |

make:
| code        | varchar(10)  | NO   | PRI | NULL    |       |
| type        | varchar(10)  | YES  | MUL | NULL    |       |
| description | varchar(255) | NO   |     | NULL    |       |

Solution

  • Your class VehicleType expects only one Make, not a Collection. You can remove the constructor and make sure to only provide a single entity, e.g. by using a type hint in the setter method.

    Alternatively you might want to change the relationship between both classes to a ManyToMany-relationship instead.