doctrine / data-fixtures

Doctrine2 ORM Data Fixtures Extensions
http://www.doctrine-project.org
MIT License
2.78k stars 224 forks source link

Idea: No Access to Entity Manager from Fixtures #121

Open sshymko opened 11 years ago

sshymko commented 11 years ago

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);
    }
}
tiger-seo commented 9 years ago

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

lavoiesl commented 9 years ago

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.