geoB
geoB

Reputation: 4704

Symfony2 - Functional Testing: container not injected into a Doctrine DataFixture - Call to a member function get() on a non-object

Attempting to build a user data fixture results in

Fatal error: Call to a member function get() on a non-object in ...\Tests\Repository\DataFixtures\LoadAdminUserData.php on line 35

line 35:

$discriminator = $this->container->get('pugx_user.manager.user_discriminator');

Complete fixture (w/ namespace edit)

 <?php

//src\Vol\VolBundle\\DataFixtures\ORM\LoadAdminUserData 

namespace Vol\VolBundle\DataFixtures\ORM;

use Doctrine\Common\DataFixtures\AbstractFixture;
use Doctrine\Common\DataFixtures\OrderedFixtureInterface;
use Doctrine\Common\Persistence\ObjectManager;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * Description of LoadAdminUserData
 *
 */
class LoadAdminUserData extends AbstractFixture implements OrderedFixtureInterface, ContainerAwareInterface
{

    /**
     * @var ContainerInterface
     */
    private $container;

    /**
     * {@inheritDoc}
     */
    public function setContainer(ContainerInterface $container = null)
    {
        $this->container = $container;
    }

    public function load(ObjectManager $manager)
    {
        $discriminator = $this->container->get('pugx_user.manager.user_discriminator');
        $discriminator->setClass('Vol\VolBundle\Entity\Admin');

        $userManager = $this->container->get('pugx_user_manager');

        $admin = $userManager->createUser();

        $admin->setUsername('bborko');
        $admin->setEmail('[email protected]');
        $admin->setPlainPassword('123456');
        $admin->setEnabled(true);

        $userManager->updateUser($admin, true);

        $this->addReference('test-user', $admin);
    }

    public function getOrder()
    {
        return 3;
    }

}

Test

<?php

//src\Vol\VolBundle\Tests\Repository

namespace Vol\VolBundle\Tests\Repository;

use Vol\VolBundle\DataFixtures\ORM\DoctrineTestCase;

/**
 * Description of AdminUserRepositoryTest
 *
 * @author George
 */
class AdminUserRepositoryTest extends DoctrineTestCase
{
   /**
     * Set up repository test
     */
    public function setUp()
    {
        $this->loadFixturesFromDirectory($this->dir);
    }

    /**
     * Test finding all countries ordered
     */
    public function testFindAll()
    {
        $focuses = $this->getRepository()->findAll();

        $this->assertCount(1, $focuses, 'Should return 1 admin user');
    }

    /**
     * Returns repository
     *
     * @return \Vol\VolBundle\Entity\Admin
     */
    protected function getRepository()
    {
        return $this->em->getRepository('\Vol\VolBundle\Entity\Admin');
    }
}

class DoctrineTestCase

<?php

//src\Vol\VolBundle\Tests\Repository

namespace Vol\VolBundle\DataFixtures\ORM;

use Doctrine\Common\DataFixtures\Purger\ORMPurger;
use Doctrine\Common\DataFixtures\Executor\ORMExecutor;
use Doctrine\Common\DataFixtures\Loader;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

/**
 * Class DoctrineTestCase
 *
 * This is the base class to load doctrine fixtures using the symfony configuration
 */
class DoctrineTestCase extends WebTestCase
{
    /**
     * @var \Symfony\Component\DependencyInjection\Container
     */
    protected $container;

    /**
     * @var \Doctrine\ORM\EntityManager
     */
    protected $em;

    /**
     * @var string
     */
    protected $environment = 'test';

    /**
     * @var bool
     */
    protected $debug = true;

    /**
     * @var string
     */
    protected $entityManagerServiceId = 'doctrine.orm.entity_manager';

    protected $dir;

    /**
     * Constructor
     *
     * @param string|null $name     Test name
     * @param array       $data     Test data
     * @param string      $dataName Data name
     */
    public function __construct($name = null, array $data = array(), $dataName = '')
    {
        parent::__construct($name, $data, $dataName);

        if (!static::$kernel) {
            static::$kernel = self::createKernel(array(
                'environment' => $this->environment,
                'debug'       => $this->debug
            ));
            static::$kernel->boot();
        }

        $this->container = static::$kernel->getContainer();
        $this->em = $this->getEntityManager();
        $this->dir = __DIR__;
    }

    /**
     * Executes fixtures
     *
     * @param \Doctrine\Common\DataFixtures\Loader $loader
     */
    protected function executeFixtures(Loader $loader)
    {
        $purger = new ORMPurger();
        $executor = new ORMExecutor($this->em, $purger);
        $executor->execute($loader->getFixtures());
    }

    /**
     * Load and execute fixtures from a directory
     *
     * @param string $directory
     */
    protected function loadFixturesFromDirectory($directory)
    {
        $loader = new Loader();
        $loader->loadFromDirectory($directory);
        $this->executeFixtures($loader);
    }

    /**
     * Returns the doctrine orm entity manager
     *
     * @return object
     */
    protected function getEntityManager()
    {
        return $this->container->get($this->entityManagerServiceId);
    }
}

Upvotes: 2

Views: 2516

Answers (1)

Nicolai Fr&#246;hlich
Nicolai Fr&#246;hlich

Reputation: 52493

Solution:

You'll have to pass the container to your fixture-loader inside the TestCase yourself.

Just use Symfony\Bridge\Doctrine\DataFixtures\ContainerAwareLoader ...

... which extends Doctrine\Common\DataFixtures\Loader and expects the container ...

... as constructor argument.

use Symfony\Bridge\Doctrine\DataFixtures\ContainerAwareLoader;

protected function loadFixturesFromDirectory($directory)
{
    $loader = new ContainerAwareLoader($this->container);
    $loader->loadFromDirectory($directory);
    $this->executeFixtures($loader);
}

When does symfony2 inject the container automatically?

The FrameworkBundle injects the container into instances of ContainerAwareInterface being controllers or commands only.

The corresponding code can be found here and here.


DataFixtures can be container-aware, too.

DoctrineFixtureBundle's Command searches for (container-aware) fixtures and injects the container.

Only fixtures that conventially live in a bundle's DataFixtures/ORM folder are processed.

A quick look at the code reveals it:

foreach ($this->getApplication()->getKernel()->getBundles() as $bundle) {
    $paths[] = $bundle->getPath().'/DataFixtures/ORM';
}

The --fixtures flag:

Appending the --fixtures flag - which can be a string or an array - to the doctrine:fixtures:load allows to add additional fixture-paths for processing.

Upvotes: 4

Related Questions