data-fixtures icon indicating copy to clipboard operation
data-fixtures copied to clipboard

Idea: No Access to Entity Manager from Fixtures

Open sshymko opened this issue 12 years ago • 2 comments

Dependency on Entity Manager

Currently, entity manager instance is passed to fixtures. A fixture in its turn uses the entity manager to persist and flush entities created by it. Correct me if I'm wrong, the only purpose of explicit persistence is to acquire identifier value. However, Doctrine entities do not operate identifiers, references between objects in memory define relations.

For example, a fixture declared in the current paradigm:

class LoadUserRoleData extends AbstractFixture
{
    public function load(ObjectManager $manager)
    {
        $adminRole = new Role();
        $adminRole->setName('admin');

        $anonymousRole = new Role;
        $anonymousRole->setName('anonymous');

        $manager->persist($adminRole);
        $manager->persist($anonymousRole);
        $manager->flush();

        $this->addReference('admin-role', $adminRole);
    }
}

Solution

The idea is that fixtures return entity objects, which are intended to be persisted. The fixtures framework collects all returned entities, persists them and flushes the entity manager. In result, there is no necessity to allow access to the entity manager from fixtures. For example:

class LoadUserRoleData extends AbstractFixture
{
    public function load()
    {
        $adminRole = new Role();
        $adminRole->setName('admin');

        $anonymousRole = new Role;
        $anonymousRole->setName('anonymous');

        $this->addReference('admin-role', $adminRole);

        return array($adminRole, $anonymousRole);
    }
}

Inheritance from Abstract Fixture Class

Another problem of the current paradigm is necessity to inherit the abstract fixture class to gain access to the references repository. The proposed approach allows to give names to fixture entities that are intended to be shared. That basically allows to eliminate dependency on the reference repository for fixtures, which only share their entities, but not use already shared ones. For example:

class LoadUserRoleData
{
    public function load()
    {
        $adminRole = new Role();
        $adminRole->setName('admin');

        $anonymousRole = new Role;
        $anonymousRole->setName('anonymous');

        return array('admin-role' => $adminRole, $anonymousRole);
    }
}

In order to retrieve shared entities, access to some sort of registry is still needed. One of the options is to provide access to the repository as part of DependentFixtureInterface, for example:

interface DependentFixtureInterface
{   
    public function getDependencies();

    public function injectDependencies(ReferenceRepository $dependencies);
}

class LoadUserData implements DependentFixtureInterface
{
    protected $_adminRole;

    public function getDependencies()
    {
        return array('MyDataFixtures\LoadUserRoleData');
    }

    public function injectDependencies(ReferenceRepository $dependencies)
    {
        $this->_adminRole = $dependencies->getReference('admin-role');
    {

    public function load()
    {
        $user = new User();
        $user->setUsername('jwage');
        $user->setPassword('test');
        $user->setRole($this->_adminRole);

        return array('admin-user' => $user);
    }
}

sshymko avatar Nov 12 '13 19:11 sshymko

you will not be able to create fixtures who`s identifier is compound index, which consist of one or more associations

tiger-seo avatar Nov 20 '14 20:11 tiger-seo

What would be the main purpose of refactoring this way? It seems to me it is adding some complexity for little gain in terms of separation of knowledge. Devs are used to work directly with the em all the time.

lavoiesl avatar Mar 22 '15 20:03 lavoiesl