いくつかの機能面をテストしたい、非常に複雑なクラスを作成しました。
したがって、symfony の WebTestCase を使用し、doctrine の遅延読み込みに依存する自己実装のインポートに対してテストします。両方の環境で正常に機能する新しい行としてデータをインポートするか、既存のデータを更新したいと考えています。後者の場合、指定されたパッケージをロードし、カタログを取得します (遅延ロードを使用)。
この部分は開発環境では問題なく動作しますが、テスト環境ではテストが失敗します。symfony2 (標準版) を使用しています。ここで私が使用しているテストを見ることができます
<?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->setUpSchema();
$this->import = new Import(self::$em);
}
public function tearDown()
{
parent::tearDown();
self::$tool->dropSchema(self::$entities);
}
public function setUpSchema()
{
self::$entities = array(
self::$em->getClassMetadata('Sulu\Bundle\TranslateBundle\Entity\Catalogue'),
self::$em->getClassMetadata('Sulu\Bundle\TranslateBundle\Entity\Code'),
self::$em->getClassMetadata('Sulu\Bundle\TranslateBundle\Entity\Location'),
self::$em->getClassMetadata('Sulu\Bundle\TranslateBundle\Entity\Package'),
self::$em->getClassMetadata('Sulu\Bundle\TranslateBundle\Entity\Translation'),
);
self::$tool->createSchema(self::$entities);
}
public function testXliff()
{
// test usual import
$this->import->setFile(__DIR__ . '/../Fixtures/import.xliff');
$this->import->setName('Import');
$this->import->setFormat(Import::XLIFF);
$this->import->setLocale('de');
$this->import->execute();
$package = self::$em->getRepository('SuluTranslateBundle:Package')->find(1);
$this->assertEquals(1, $package->getId());
$this->assertEquals('Import', $package->getName());
$catalogue = self::$em->getRepository('SuluTranslateBundle:Catalogue')->find(1);
$this->assertEquals(1, $catalogue->getId());
$this->assertEquals('de', $catalogue->getLocale());
$codes = self::$em->getRepository('SuluTranslateBundle:Code')->findAll();
$this->assertEquals(1, $codes[0]->getId());
$this->assertEquals('sulu.great', $codes[0]->getCode());
$this->assertEquals(true, $codes[0]->getBackend());
$this->assertEquals(true, $codes[0]->getFrontend());
$this->assertEquals(null, $codes[0]->getLength());
$this->assertEquals(2, $codes[1]->getId());
$this->assertEquals('sulu.open', $codes[1]->getCode());
$this->assertEquals(true, $codes[1]->getBackend());
$this->assertEquals(true, $codes[1]->getFrontend());
$this->assertEquals(null, $codes[1]->getLength());
$translations = self::$em->getRepository('SuluTranslateBundle:Translation')->findAll();
$this->assertEquals('Sulu ist toll!', $translations[0]->getValue());
$this->assertEquals('Sulu ist OpenSource!', $translations[1]->getValue());
// test new import
$this->import->setFile(__DIR__ . '/../Fixtures/import_better.xliff');
$this->import->setName('Import Update');
$this->import->setFormat(Import::XLIFF);
$this->import->setLocale('de');
$this->import->setPackageId(1);
$this->import->execute();
$package = self::$em->getRepository('SuluTranslateBundle:Package')->find(1);
$this->assertEquals(1, $package->getId());
$this->assertEquals('Import Update', $package->getName());
$catalogue = self::$em->getRepository('SuluTranslateBundle:Catalogue')->find(1);
$this->assertEquals(1, $catalogue->getId());
$this->assertEquals('de', $catalogue->getLocale());
$codes = self::$em->getRepository('SuluTranslateBundle:Code')->findAll();
$this->assertEquals(1, $codes[0]->getId());
$this->assertEquals('sulu.great', $codes[0]->getCode());
$this->assertEquals(true, $codes[0]->getBackend());
$this->assertEquals(true, $codes[0]->getFrontend());
$this->assertEquals(null, $codes[0]->getLength());
$this->assertEquals(2, $codes[1]->getId());
$this->assertEquals('sulu.open', $codes[1]->getCode());
$this->assertEquals(true, $codes[1]->getBackend());
$this->assertEquals(true, $codes[1]->getFrontend());
$this->assertEquals(null, $codes[1]->getLength());
$this->assertEquals('sulu.very.great', $codes[2]->getCode());
$this->assertEquals(true, $codes[2]->getBackend());
$this->assertEquals(true, $codes[2]->getFrontend());
$this->assertEquals(null, $codes[2]->getLength());
$this->assertEquals('sulu.even.open', $codes[3]->getCode());
$this->assertEquals(true, $codes[3]->getBackend());
$this->assertEquals(true, $codes[3]->getFrontend());
$this->assertEquals(null, $codes[3]->getLength());
$translations = self::$em->getRepository('SuluTranslateBundle:Translation')->findAll();
$this->assertEquals('Sulu ist wirklich toll!', $translations[0]->getValue());
$this->assertEquals('Sulu ist OpenSource!', $translations[1]->getValue());
$this->assertEquals('Sulu ist sehr toll!', $translations[2]->getValue());
$this->assertEquals('Sulu ist sogar OpenSource!', $translations[3]->getValue());
}
}
そして、ここで私の問題を引き起こしている機能を見ることができます:
public function execute()
{
// get correct loader according to format
$loader = null;
switch ($this->getFormat()) {
case self::XLIFF:
$loader = new XliffFileLoader();
break;
}
$newCatalogue = true;
if ($this->getPackageId() == null) {
// create a new package and catalogue for the import
$package = new Package();
$catalogue = new Catalogue();
$catalogue->setPackage($package);
$this->em->persist($package);
$this->em->persist($catalogue);
} else {
// load the given package and catalogue
$package = $this->em->getRepository('SuluTranslateBundle:Package')
->find($this->getPackageId());
if (!$package) {
// If the given package is not existing throw an exception
throw new PackageNotFoundException($this->getPackageId());
}
// find the catalogue from this package matching the given locale
$catalogue = null;
foreach ($package->getCatalogues() as $packageCatalogue) {
/** @var $packageCatalogue Catalogue */
if ($packageCatalogue->getLocale() == $this->getLocale()) {
$catalogue = $packageCatalogue;
$newCatalogue = false;
}
}
// if no catalogue is found create a new one
if ($newCatalogue) {
$catalogue = new Catalogue();
$catalogue->setPackage($package);
$this->em->persist($catalogue);
}
}
$package->setName($this->getName());
$catalogue->setLocale($this->getLocale());
// load the file, and create a new code/translation combination for every message
$fileCatalogue = $loader->load($this->getFile(), $this->getLocale());
foreach ($fileCatalogue->all()['messages'] as $key => $message) {
// Check if code is already existing in current catalogue
if (!$newCatalogue && ($translate = $catalogue->findTranslation($key))) {
// Update the old code and translate
$translate->setValue($message);
} else {
// Create new code and translate
$code = new Code();
$code->setPackage($package);
$code->setCode($key);
$code->setBackend(true);
$code->setFrontend(true);
$translate = new Translation();
$translate->setCode($code);
$translate->setValue($message);
$translate->setCatalogue($catalogue);
$this->em->persist($code);
$this->em->flush(); //FIXME no flush in between, if possible
$this->em->persist($translate);
}
}
// save all the changes to the database
$this->em->flush();
}
問題は、パッケージからカタログを取得しようとする行が何も返さないことです。デバッグすると、パッケージがロードされていることがわかります。catalogues-property は PersistentCollection であり、要素 (_elements-array にはまだありません) を含む ArrayCollection があるようです。次のスクリーンショットは、うまくいけばそれをよりよく説明しています:
編集:問題はキャッシュメカニズムに関連していると思います。テストを実行する前に行がすでに存在する場合、データが読み取られます。そうでない場合は、次のスニペットのように結果キャッシュを削除しようとしました。
public function testXliff()
{
$cacheDriver = self::$em->getConfiguration()->getResultCacheImpl();
// test usual import
$this->import->setFile(__DIR__ . '/../Fixtures/import.xliff');
$this->import->setName('Import');
$this->import->setFormat(Import::XLIFF);
$this->import->setLocale('de');
$this->import->execute();
$cacheDriver->deleteAll();
// test new import
$this->import->setFile(__DIR__ . '/../Fixtures/import_better.xliff');
$this->import->setName('Import Update');
$this->import->setFormat(Import::XLIFF);
$this->import->setLocale('de');
$this->import->setPackageId(1);
$this->import->execute();
$cacheDriver->deleteAll();
// test new import with new language code
$this->import->setFile(__DIR__ . '/../Fixtures/import.xliff');
$this->import->setName('Import');
$this->import->setFormat(Import::XLIFF);
$this->import->setLocale('en');
$this->import->execute();
}
EDIT2:テストを実行するために管理しましたが、私の意見では、それは単なる回避策です... $em->clear() で「キャッシュ」をクリアすると、結果は正しいです。もちろん、私はこの問題をデバッグし、EntityManager の identityMap フィールドからのオブジェクトが使用されていることに気付きました。これには、既に初期化されたオブジェクトが含まれています。そのため、すべてのコレクションで初期化フラグが true に設定されているため、遅延読み込み部分は実行されません。それはバグですか?