symfonydoctrine-orm

Zenstruck/Foundy doesn't set the foreign key when loading the fixtures


I'm using Symfony 7 and the ZenstruckFoundryBundle to generate fixtures. For whatever reason I always get this error

I've already debugged the ids, they are not empty.

  SQLSTATE[23502]: Not null violation: 7 ERROR:  null value in column "organization_id" of relation "project" vi   
  olates not-null constraint                                                                                       
  DETAIL:  Failing row contains (c2a33118-c009-37e2-9c62-6a1017ae12b0, null, Howe-Kling, Non et non explicabo op   
  tio sunt at. Ut quia doloribus distinctio..., null).                                                        

DataFixtures

namespace App\DataFixtures;

use App\Application\Service\UuidGeneratorInterface;
use App\Factory\Projects\ProjectFactory;
use App\Factory\Users\OrganizationFactory;
use App\Factory\Users\ProfileFactory;
use App\Factory\Users\UserFactory;
use Doctrine\Bundle\FixturesBundle\Fixture;
use Doctrine\Persistence\ObjectManager;

class AppFixtures extends Fixture
{
    public function __construct(
        private UuidGeneratorInterface $uuidGenerator,
    ) {
    }

    public function load(ObjectManager $manager): void
    {
        $user = UserFactory::createOne([
            'email' => 'test@user.com',
            'password' => 'Password1234!',
            'profile' => ProfileFactory::createOne([
                'firstName' => 'John',
                'lastName' => 'Doe'
            ]),
            'organization' => OrganizationFactory::createOne([
                'name' => 'ACME',
                'companySize' => '100-499',
                'industry' => 'Software'
            ]),
        ]);

        $projects = ProjectFactory::createOne([
            'organizationId' => $user->getOrganization()->getId(),
            'ownerId' => $user->getId()
        ]);
    }
}

Project Entity

namespace App\Capabilities\Projects\Domain;

use App\Capabilities\Projects\Infrastructure\Persistence\ProjectsRepository;
use Doctrine\ORM\Mapping as ORM;

#[ORM\Entity(
    repositoryClass: ProjectsRepository::class
)]
class Project
{
    #[ORM\Id]
    #[ORM\GeneratedValue(strategy: 'NONE')]
    #[ORM\Column(type: 'uuid')]
    private string $id;

    #[ORM\Column(type: 'string', length: 128)]
    private string $name;

    #[ORM\Column(type: 'text')]
    private string $description;

    #[ORM\Column( type: 'uuid')]
    private string $organizationId;

    #[ORM\Column(type: 'uuid')]
    private string $ownerId;

    #[ORM\OneToOne(targetEntity: Organization::class)]
    private Organization $organization;

    #[ORM\OneToOne(targetEntity: Owner::class)]
    private Owner $owner;

    // No more fields, just methods after this
}

Solution

  • Why do you have an ownerId and organizationId fields? That entity seems incorrectly defined.

    There are already relationships defined on $organization and. $owner

    Remove those two fields, since they are likely creating a conflicting mapping with your actual relationships.

    Then your fixture should be fixed by doing something like:

    namespace App\DataFixtures;
    
    use App\Application\Service\UuidGeneratorInterface;
    use App\Factory\Projects\ProjectFactory;
    use App\Factory\Users\OrganizationFactory;
    use App\Factory\Users\ProfileFactory;
    use App\Factory\Users\UserFactory;
    use Doctrine\Bundle\FixturesBundle\Fixture;
    use Doctrine\Persistence\ObjectManager;
    
    class AppFixtures extends Fixture
    {
        public function __construct(
            private UuidGeneratorInterface $uuidGenerator,
        ) {
        }
    
        public function load(ObjectManager $manager): void
        {
            $organization = OrganizationFactory::createOne([
                    'name' => 'ACME',
                    'companySize' => '100-499',
                    'industry' => 'Software'
                ]);
    
    
            $user = UserFactory::createOne([
                'email' => 'test@user.com',
                'password' => 'Password1234!',
                'profile' => ProfileFactory::createOne([
                    'firstName' => 'John',
                    'lastName' => 'Doe'
                ]),
                'organization' => $organization,
            ]);
    
            $projects = ProjectFactory::createOne([
                'organization' => $organization,
                'owner' => $user
            ]);
        }
    }
    

    Alternatively, do not use a table relationship with an ORM enforced FK, and simply have a scalar field to hold the relationship id. One or the other, not both. Depending what you want.