Note that there are some explanatory texts on larger screens.

plurals
  1. PODoctrine Lazy Loading in Symfony Test environment
    primarykey
    data
    text
    <p>I have written quite a complicated class, on which I want to test some functional aspects. </p> <p>Therefore I use the WebTestCase from symfony, and test against an self-implemented import, in which I rely on doctrine's lazy loading. I want to import the data as new rows, which works fine in both environments, or update already existing data. In the latter case I want to load the given package, and get the catalogue (with lazy loading).</p> <p>This part works fine in the dev-environment, but the tests fail in the testing-environment. I am using symfony2 (standard edition). Here you can see the test I am using</p> <pre><code>&lt;?php namespace Sulu\Bundle\TranslateBundle\Tests\Translate; use Sulu\Bundle\CoreBundle\Tests\DatabaseTestCase; use Sulu\Bundle\TranslateBundle\Translate\Import; class ImportTest extends DatabaseTestCase { /** * @var Import */ protected $import; /** * @var array */ protected static $entities; public function setUp() { $this-&gt;setUpSchema(); $this-&gt;import = new Import(self::$em); } public function tearDown() { parent::tearDown(); self::$tool-&gt;dropSchema(self::$entities); } public function setUpSchema() { self::$entities = array( self::$em-&gt;getClassMetadata('Sulu\Bundle\TranslateBundle\Entity\Catalogue'), self::$em-&gt;getClassMetadata('Sulu\Bundle\TranslateBundle\Entity\Code'), self::$em-&gt;getClassMetadata('Sulu\Bundle\TranslateBundle\Entity\Location'), self::$em-&gt;getClassMetadata('Sulu\Bundle\TranslateBundle\Entity\Package'), self::$em-&gt;getClassMetadata('Sulu\Bundle\TranslateBundle\Entity\Translation'), ); self::$tool-&gt;createSchema(self::$entities); } public function testXliff() { // test usual import $this-&gt;import-&gt;setFile(__DIR__ . '/../Fixtures/import.xliff'); $this-&gt;import-&gt;setName('Import'); $this-&gt;import-&gt;setFormat(Import::XLIFF); $this-&gt;import-&gt;setLocale('de'); $this-&gt;import-&gt;execute(); $package = self::$em-&gt;getRepository('SuluTranslateBundle:Package')-&gt;find(1); $this-&gt;assertEquals(1, $package-&gt;getId()); $this-&gt;assertEquals('Import', $package-&gt;getName()); $catalogue = self::$em-&gt;getRepository('SuluTranslateBundle:Catalogue')-&gt;find(1); $this-&gt;assertEquals(1, $catalogue-&gt;getId()); $this-&gt;assertEquals('de', $catalogue-&gt;getLocale()); $codes = self::$em-&gt;getRepository('SuluTranslateBundle:Code')-&gt;findAll(); $this-&gt;assertEquals(1, $codes[0]-&gt;getId()); $this-&gt;assertEquals('sulu.great', $codes[0]-&gt;getCode()); $this-&gt;assertEquals(true, $codes[0]-&gt;getBackend()); $this-&gt;assertEquals(true, $codes[0]-&gt;getFrontend()); $this-&gt;assertEquals(null, $codes[0]-&gt;getLength()); $this-&gt;assertEquals(2, $codes[1]-&gt;getId()); $this-&gt;assertEquals('sulu.open', $codes[1]-&gt;getCode()); $this-&gt;assertEquals(true, $codes[1]-&gt;getBackend()); $this-&gt;assertEquals(true, $codes[1]-&gt;getFrontend()); $this-&gt;assertEquals(null, $codes[1]-&gt;getLength()); $translations = self::$em-&gt;getRepository('SuluTranslateBundle:Translation')-&gt;findAll(); $this-&gt;assertEquals('Sulu ist toll!', $translations[0]-&gt;getValue()); $this-&gt;assertEquals('Sulu ist OpenSource!', $translations[1]-&gt;getValue()); // test new import $this-&gt;import-&gt;setFile(__DIR__ . '/../Fixtures/import_better.xliff'); $this-&gt;import-&gt;setName('Import Update'); $this-&gt;import-&gt;setFormat(Import::XLIFF); $this-&gt;import-&gt;setLocale('de'); $this-&gt;import-&gt;setPackageId(1); $this-&gt;import-&gt;execute(); $package = self::$em-&gt;getRepository('SuluTranslateBundle:Package')-&gt;find(1); $this-&gt;assertEquals(1, $package-&gt;getId()); $this-&gt;assertEquals('Import Update', $package-&gt;getName()); $catalogue = self::$em-&gt;getRepository('SuluTranslateBundle:Catalogue')-&gt;find(1); $this-&gt;assertEquals(1, $catalogue-&gt;getId()); $this-&gt;assertEquals('de', $catalogue-&gt;getLocale()); $codes = self::$em-&gt;getRepository('SuluTranslateBundle:Code')-&gt;findAll(); $this-&gt;assertEquals(1, $codes[0]-&gt;getId()); $this-&gt;assertEquals('sulu.great', $codes[0]-&gt;getCode()); $this-&gt;assertEquals(true, $codes[0]-&gt;getBackend()); $this-&gt;assertEquals(true, $codes[0]-&gt;getFrontend()); $this-&gt;assertEquals(null, $codes[0]-&gt;getLength()); $this-&gt;assertEquals(2, $codes[1]-&gt;getId()); $this-&gt;assertEquals('sulu.open', $codes[1]-&gt;getCode()); $this-&gt;assertEquals(true, $codes[1]-&gt;getBackend()); $this-&gt;assertEquals(true, $codes[1]-&gt;getFrontend()); $this-&gt;assertEquals(null, $codes[1]-&gt;getLength()); $this-&gt;assertEquals('sulu.very.great', $codes[2]-&gt;getCode()); $this-&gt;assertEquals(true, $codes[2]-&gt;getBackend()); $this-&gt;assertEquals(true, $codes[2]-&gt;getFrontend()); $this-&gt;assertEquals(null, $codes[2]-&gt;getLength()); $this-&gt;assertEquals('sulu.even.open', $codes[3]-&gt;getCode()); $this-&gt;assertEquals(true, $codes[3]-&gt;getBackend()); $this-&gt;assertEquals(true, $codes[3]-&gt;getFrontend()); $this-&gt;assertEquals(null, $codes[3]-&gt;getLength()); $translations = self::$em-&gt;getRepository('SuluTranslateBundle:Translation')-&gt;findAll(); $this-&gt;assertEquals('Sulu ist wirklich toll!', $translations[0]-&gt;getValue()); $this-&gt;assertEquals('Sulu ist OpenSource!', $translations[1]-&gt;getValue()); $this-&gt;assertEquals('Sulu ist sehr toll!', $translations[2]-&gt;getValue()); $this-&gt;assertEquals('Sulu ist sogar OpenSource!', $translations[3]-&gt;getValue()); } } </code></pre> <p>And here you can see the function that is causing my problem:</p> <pre><code>public function execute() { // get correct loader according to format $loader = null; switch ($this-&gt;getFormat()) { case self::XLIFF: $loader = new XliffFileLoader(); break; } $newCatalogue = true; if ($this-&gt;getPackageId() == null) { // create a new package and catalogue for the import $package = new Package(); $catalogue = new Catalogue(); $catalogue-&gt;setPackage($package); $this-&gt;em-&gt;persist($package); $this-&gt;em-&gt;persist($catalogue); } else { // load the given package and catalogue $package = $this-&gt;em-&gt;getRepository('SuluTranslateBundle:Package') -&gt;find($this-&gt;getPackageId()); if (!$package) { // If the given package is not existing throw an exception throw new PackageNotFoundException($this-&gt;getPackageId()); } // find the catalogue from this package matching the given locale $catalogue = null; foreach ($package-&gt;getCatalogues() as $packageCatalogue) { /** @var $packageCatalogue Catalogue */ if ($packageCatalogue-&gt;getLocale() == $this-&gt;getLocale()) { $catalogue = $packageCatalogue; $newCatalogue = false; } } // if no catalogue is found create a new one if ($newCatalogue) { $catalogue = new Catalogue(); $catalogue-&gt;setPackage($package); $this-&gt;em-&gt;persist($catalogue); } } $package-&gt;setName($this-&gt;getName()); $catalogue-&gt;setLocale($this-&gt;getLocale()); // load the file, and create a new code/translation combination for every message $fileCatalogue = $loader-&gt;load($this-&gt;getFile(), $this-&gt;getLocale()); foreach ($fileCatalogue-&gt;all()['messages'] as $key =&gt; $message) { // Check if code is already existing in current catalogue if (!$newCatalogue &amp;&amp; ($translate = $catalogue-&gt;findTranslation($key))) { // Update the old code and translate $translate-&gt;setValue($message); } else { // Create new code and translate $code = new Code(); $code-&gt;setPackage($package); $code-&gt;setCode($key); $code-&gt;setBackend(true); $code-&gt;setFrontend(true); $translate = new Translation(); $translate-&gt;setCode($code); $translate-&gt;setValue($message); $translate-&gt;setCatalogue($catalogue); $this-&gt;em-&gt;persist($code); $this-&gt;em-&gt;flush(); //FIXME no flush in between, if possible $this-&gt;em-&gt;persist($translate); } } // save all the changes to the database $this-&gt;em-&gt;flush(); } </code></pre> <p>The problem is that the line where I try to get the catalogues from the package doesn't return anything. When I debug I can see that the package is loaded, and the catalogues-property is a PersistentCollection, which seems to have an ArrayCollection containing a element (which is not in the _elements-array yet). The following screenshot hopefully explains it better:</p> <p><img src="https://i.stack.imgur.com/UgqtU.png" alt="enter image description here"></p> <p>EDIT: I think the problem is related to the caching mechanism. If the row is already existent before executing the test, the data is read. Otherwise not, I already tried to delete the result cache like in the following snippet:</p> <pre><code>public function testXliff() { $cacheDriver = self::$em-&gt;getConfiguration()-&gt;getResultCacheImpl(); // test usual import $this-&gt;import-&gt;setFile(__DIR__ . '/../Fixtures/import.xliff'); $this-&gt;import-&gt;setName('Import'); $this-&gt;import-&gt;setFormat(Import::XLIFF); $this-&gt;import-&gt;setLocale('de'); $this-&gt;import-&gt;execute(); $cacheDriver-&gt;deleteAll(); // test new import $this-&gt;import-&gt;setFile(__DIR__ . '/../Fixtures/import_better.xliff'); $this-&gt;import-&gt;setName('Import Update'); $this-&gt;import-&gt;setFormat(Import::XLIFF); $this-&gt;import-&gt;setLocale('de'); $this-&gt;import-&gt;setPackageId(1); $this-&gt;import-&gt;execute(); $cacheDriver-&gt;deleteAll(); // test new import with new language code $this-&gt;import-&gt;setFile(__DIR__ . '/../Fixtures/import.xliff'); $this-&gt;import-&gt;setName('Import'); $this-&gt;import-&gt;setFormat(Import::XLIFF); $this-&gt;import-&gt;setLocale('en'); $this-&gt;import-&gt;execute(); } </code></pre> <p>EDIT2: I managed it to get the tests running, but in my opinion it is just a dirty workaround... If I clear the "cache" with $em->clear() the results are correct. Of course I have debugged this problem, and realized that the objects from the identityMap-field in the EntityManager are used, which already contain initialized objects. So all the collections have the initialized-flag set on true, so that the lazy loading part is not executed. Is that a bug?</p>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload