Doctrine и светильники: вопрос с отношениями - PullRequest
0 голосов
/ 06 марта 2020

Я пытаюсь создать набор приборов для моего нового проекта Symfony 4. Я столкнулся с проблемой, связанной с некоторыми отношениями между моими сущностями.

Здесь вы можете найти соответствующие сущности:

Пользователь

class User implements UserInterface
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=180, unique=true)
     */
    private $username;

    /**
     * @var array
     *
     * @ORM\Column(type="json")
     */
    private $roles = [];

    /**
     * @var string The hashed password
     * @ORM\Column(type="string")
     */
    private $password;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    private $firstname;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    private $insertion;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    private $lastname;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $email;

    /**
     * @ORM\ManyToOne(targetEntity="App\Entity\UserGroup", inversedBy="users")
     * @ORM\JoinColumn(nullable=false)
     */
    private $userGroup;
}

UserGroup

class UserGroup
{
    /**
     * @ORM\Id()
     * @ORM\GeneratedValue()
     * @ORM\Column(type="integer")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     */
    private $title;

    /**
     * @ORM\OneToMany(targetEntity="App\Entity\User", mappedBy="userGroup")
     */
    private $users;
}

Я решил создать класс BaseFixture с некоторыми методами. Я нашел эту идею в Symfonycast: https://symfonycasts.com/screencast/doctrine-relations/awesome-random-fixtures.

Вот она:

/**
 * Class BaseFixture
 * @package App\DataFixtures
 */
abstract class BaseFixture extends Fixture
{
    /** @var ObjectManager */
    private $manager;

    /** @var Generator */
    protected $faker;

    /**
     * @var array
     */
    private $referencesIndex = [];

    /**
     * @param ObjectManager $manager
     * @return mixed
     */
    abstract protected function loadData(ObjectManager $manager);

    /**
     * @param ObjectManager $manager
     */
    public function load(ObjectManager $manager)
    {
        $this->manager = $manager;
        $this->faker = Factory::create();

        $this->loadData($manager);
    }

    /**
     * @param string $className
     * @param int $count
     * @param callable $factory
     */
    protected function createMany(string $className, int $count, callable $factory)
    {
        for ($i = 0; $i < $count; $i++) {

            $entity = new $className();
            $factory($entity, $i);

            $this->manager->persist($entity);
            $this->addReference($className . '_' . $i, $entity);
        }
    }

    /**
     * @param string $className
     * @return object
     * @throws Exception
     */
    protected function getRandomReference(string $className)
    {
        if (!isset($this->referencesIndex[$className])) {

            $this->referencesIndex[$className] = [];

            foreach ($this->referenceRepository->getReferences() as $key => $ref) {

                if (strpos($key, $className.'_') === 0) {
                    $this->referencesIndex[$className][] = $key;
                }
            }
        }

        if (empty($this->referencesIndex[$className])) {
            throw new Exception(sprintf('Cannot find any references for class "%s"', $className));
        }

        $randomReferenceKey = $this->faker->randomElement($this->referencesIndex[$className]);

        return $this->getReference($randomReferenceKey);
    }

    /**
     * @param string $className
     * @param int $count
     * @return array
     * @throws Exception
     */
    protected function getRandomReferences(string $className, int $count)
    {
        $references = [];

        while (count($references) < $count) {
            $references[] = $this->getRandomReference($className);
        }

        return $references;
    }
}

И после, у меня есть 2 прибора:

/**
 * Class UserGroupFixtures
 * @package App\DataFixtures
 */
class UserGroupFixtures extends Fixture
{
    /**
     * @param ObjectManager $manager
     */
    public function load(ObjectManager $manager)
    {

        /** @var UserGroup $adminUserGroup */
        $adminUserGroup = new UserGroup();
        $adminUserGroup->setTitle('admin');

        $manager->persist($adminUserGroup);

        /** @var UserGroup $adminUserGroup */
        $userUserGroup = new UserGroup();
        $userUserGroup->setTitle('user');

        $manager->persist($userUserGroup);

        /** @var UserGroup $adminUserGroup */
        $viewerUserGroup = new UserGroup();
        $viewerUserGroup->setTitle('viewer');

        $manager->persist($viewerUserGroup);

        $manager->flush();
    }
}

И пользовательское приспособление:

class UserFixtures extends BaseFixture implements DependentFixtureInterface
{
    /**
     * @var array
     */
    private static $userRoles = [
        ["ROLE_ADMIN"],
        ["ROLE_USER"]
    ];

    /**
     * @var array
     */
    private static $userInsertion = [
        'van',
        'de',
        ''
    ];

    private $passwordEncoder;

    /**
     * UserFixtures constructor.
     * @param UserPasswordEncoderInterface $passwordEncoder
     */
    public function __construct(UserPasswordEncoderInterface $passwordEncoder)
    {
        $this->passwordEncoder = $passwordEncoder;
    }

    /**
     * @param ObjectManager $manager
     */
    protected function loadData(ObjectManager $manager)
    {
        $this->createMany(User::class, 10, function(User $user) use ($manager) {

            $user->setUsername($this->faker->userName);
            $user->setRoles($this->faker->randomElement(self::$userRoles));
            $user->setPassword($this->passwordEncoder->encodePassword($user, 'ACTIVO'));
            $user->setFirstname($this->faker->firstName);
            $user->setLastname($this->faker->lastName);
            $user->setInsertion($this->faker->randomElement(self::$userInsertion));
            $user->setEmail($this->faker->email);
            $user->setDateCreated($this->faker->dateTime);
            $user->setDateUpdate($this->faker->dateTime);
            $user->setUnsubscribed($this->faker->boolean(15));
            $user->setDateUnsubscribed($this->faker->dateTime);

            $user->setUserGroup($this->getRandomReference(UserGroup::class));
        });

        $manager->flush();
    }

    /**
     * @return array|string
     */
    public function getDependencies()
    {
        return [UserGroupFixtures::class];
    }
}

Как вы можете видеть, я использую функцию getDependencies (), потому что приспособления для UserGroup должны существовать до User.

Когда я запускаю команду для загрузки приборов, UserGroupFixtures вызывается перед UserGroup, но .... Я сталкиваюсь с ошибкой, расположенной в файле BaseFixture, в этой строке:

if (empty($this->referencesIndex[$className])) {
    throw new Exception(sprintf('Cannot find any references for class "%s"', $className));
}

Может быть полезна некоторая помощь, так как трудно отладить приборы;)

1 Ответ

1 голос
/ 06 марта 2020

Как уже отмечалось, проблема заключается в том, что вы не сохраняете экземпляры UserGroup в ссылках в первом приборе. Вы можете попробовать обновить класс UserGroupFixtures следующим образом:

/**
 * Class UserGroupFixtures
 * @package App\DataFixtures
 */
class UserGroupFixtures extends Fixture
{
    /**
     * @param ObjectManager $manager
     */
    public function load(ObjectManager $manager)
    {
        /** @var UserGroup $adminUserGroup */
        $adminUserGroup = new UserGroup();
        $adminUserGroup->setTitle('admin');

        $manager->persist($adminUserGroup);
        $this->addReference(UserGroup::class . '_1', $adminUserGroup);

        /** @var UserGroup $adminUserGroup */
        $userUserGroup = new UserGroup();
        $userUserGroup->setTitle('user');

        $manager->persist($userUserGroup);
        $this->addReference(UserGroup::class . '_2', $userUserGroup);

        /** @var UserGroup $adminUserGroup */
        $viewerUserGroup = new UserGroup();
        $viewerUserGroup->setTitle('viewer');

        $manager->persist($viewerUserGroup);
        $this->addReference(UserGroup::class . '_3', $viewerUserGroup);

        $manager->flush();
    }
}
...