diff --git a/src/Bridge/Doctrine/Persister/ManagerRegistryPersister.php b/src/Bridge/Doctrine/Persister/ManagerRegistryPersister.php new file mode 100644 index 00000000..2f6a9a11 --- /dev/null +++ b/src/Bridge/Doctrine/Persister/ManagerRegistryPersister.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Fidry\AliceDataFixtures\Bridge\Doctrine\Persister; + +use Doctrine\Common\Persistence\ManagerRegistry; +use Fidry\AliceDataFixtures\Persistence\PersisterInterface; +use function get_class; +use function implode; +use InvalidArgumentException; +use Nelmio\Alice\IsAServiceTrait; +use function sprintf; + +/** + * @final + */ +class ManagerRegistryPersister implements PersisterInterface +{ + use IsAServiceTrait; + + private $registry; + + /** + * @var PersisterInterface[] + */ + private $persisters = []; + + public function __construct(ManagerRegistry $registry) + { + $this->registry = $registry; + + $managers = $registry->getManagers(); + + foreach ($managers as $manager) { + $this->persisters[get_class($manager)] = new ObjectManagerPersister($manager); + } + } + + /** + * @inheritdoc + */ + public function persist($object) + { + $persister = $this->getPersisterForClass(get_class($object)); + + $persister->persist($object); + } + + /** + * @inheritdoc + */ + public function flush() + { + foreach ($this->persisters as $persister) { + $persister->flush(); + } + } + + private function getPersisterForClass(string $class): PersisterInterface + { + $manager = $this->registry->getManagerForClass($class); + + if (null === $manager) { + throw new InvalidArgumentException( + sprintf( + 'Could not find a manager for the class "%s". Known managers: "%s"', + $class, + implode('", "', $this->registry->getManagerNames()) + ) + ); + } + + return $this->persisters[get_class($manager)]; + } +} diff --git a/src/Bridge/Doctrine/Persister/ObjectManagerPersister.php b/src/Bridge/Doctrine/Persister/ObjectManagerPersister.php index f8946c89..7efa9627 100644 --- a/src/Bridge/Doctrine/Persister/ObjectManagerPersister.php +++ b/src/Bridge/Doctrine/Persister/ObjectManagerPersister.php @@ -23,7 +23,7 @@ use Fidry\AliceDataFixtures\Persistence\PersisterInterface; use Nelmio\Alice\IsAServiceTrait; -class ObjectManagerPersister implements PersisterInterface +/* final */ class ObjectManagerPersister implements PersisterInterface { use IsAServiceTrait; diff --git a/src/Bridge/Doctrine/Purger/ManagerRegistryPurger.php b/src/Bridge/Doctrine/Purger/ManagerRegistryPurger.php new file mode 100644 index 00000000..6c840f68 --- /dev/null +++ b/src/Bridge/Doctrine/Purger/ManagerRegistryPurger.php @@ -0,0 +1,74 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Fidry\AliceDataFixtures\Bridge\Doctrine\Persister; + +use function array_map; +use Doctrine\Common\Persistence\ManagerRegistry; +use Doctrine\Common\Persistence\ObjectManager; +use Fidry\AliceDataFixtures\Bridge\Doctrine\Purger\ObjectManagerPurger; +use Fidry\AliceDataFixtures\Persistence\PurgeMode; +use Fidry\AliceDataFixtures\Persistence\PurgerFactoryInterface; +use Fidry\AliceDataFixtures\Persistence\PurgerInterface; +use InvalidArgumentException; +use Nelmio\Alice\IsAServiceTrait; + +/** + * @final + */ +/* final */ class ManagerRegistryPurger implements PurgerInterface, PurgerFactoryInterface +{ + use IsAServiceTrait; + + private $registry; + private $purgeMode; + + /** + * @var PurgerInterface[] + */ + private $purgers = []; + + public function __construct(ManagerRegistry $registry, PurgeMode $purgeMode = null) + { + $this->registry = $registry; + + $this->purgers = array_map( + function (ObjectManager $manager) use ($purgeMode): PurgerInterface { + return new ObjectManagerPurger($manager, $purgeMode); + }, + $registry->getManagers() + ); + } + + /** + * @inheritdoc + */ + public function create(PurgeMode $mode, PurgerInterface $purger = null): PurgerInterface + { + if (null !== $purger) { + throw new InvalidArgumentException('Cannot create a new purger from an existing one.'); + } + + return new self($this->registry, $mode); + } + + /** + * @inheritdoc + */ + public function purge(): void + { + foreach ($this->purgers as $purger) { + $purger->purge(); + } + } +} diff --git a/src/Bridge/Doctrine/Purger/ObjectManagerPurger.php b/src/Bridge/Doctrine/Purger/ObjectManagerPurger.php new file mode 100644 index 00000000..13075bc5 --- /dev/null +++ b/src/Bridge/Doctrine/Purger/ObjectManagerPurger.php @@ -0,0 +1,144 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace Fidry\AliceDataFixtures\Bridge\Doctrine\Purger; + +use Doctrine\Common\DataFixtures\Purger\MongoDBPurger as DoctrineMongoDBPurger; +use Doctrine\Common\DataFixtures\Purger\ORMPurger as DoctrineOrmPurger; +use Doctrine\Common\DataFixtures\Purger\PHPCRPurger as DoctrinePhpCrPurger; +use Doctrine\Common\DataFixtures\Purger\PurgerInterface as DoctrinePurgerInterface; +use Doctrine\Common\Persistence\ObjectManager; +use Doctrine\DBAL\Driver\AbstractMySQLDriver; +use Doctrine\ODM\MongoDB\DocumentManager as DoctrineMongoDocumentManager; +use Doctrine\ODM\PHPCR\DocumentManager as DoctrinePhpCrDocumentManager; +use Doctrine\ORM\EntityManagerInterface; +use Fidry\AliceDataFixtures\Persistence\PurgeMode; +use Fidry\AliceDataFixtures\Persistence\PurgerFactoryInterface; +use Fidry\AliceDataFixtures\Persistence\PurgerInterface; +use InvalidArgumentException; +use Nelmio\Alice\IsAServiceTrait; + +/** + * Bridge for Doctrine purger. + * + * @author Vincent CHALAMON + * @final + */ +/* final */ class ObjectManagerPurger implements PurgerInterface, PurgerFactoryInterface +{ + use IsAServiceTrait; + + private $manager; + private $purgeMode; + private $purger; + + public function __construct(ObjectManager $manager, PurgeMode $purgeMode = null) + { + $this->manager = $manager; + $this->purgeMode = $purgeMode; + + $this->purger = static::createPurger($manager, $purgeMode); + } + + /** + * @inheritdoc + */ + public function create(PurgeMode $mode, PurgerInterface $purger = null): PurgerInterface + { + if (null === $purger) { + return new self($this->manager, $mode); + } + + if ($purger instanceof DoctrinePurgerInterface) { + $manager = $purger->getObjectManager(); + } elseif ($purger instanceof self) { + $manager = $purger->manager; + } else { + throw new InvalidArgumentException( + sprintf( + 'Expected purger to be either and instance of "%s" or "%s". Got "%s".', + DoctrinePurgerInterface::class, + __CLASS__, + get_class($purger) + ) + ); + } + + if (null === $manager) { + throw new InvalidArgumentException( + sprintf( + 'Expected purger "%s" to have an object manager, got "null" instead.', + get_class($purger) + ) + ); + } + + return new self($manager, $mode); + } + + /** + * @inheritdoc + */ + public function purge(): void + { + // Because MySQL rocks, you got to disable foreign key checks when doing a TRUNCATE unlike in for example + // PostgreSQL. This ideally should be done in the Purger of doctrine/data-fixtures but meanwhile we are doing + // it here. + // See the progress in https://github.com/doctrine/data-fixtures/pull/272 + $truncateOrm = ( + $this->purger instanceof DoctrineOrmPurger + && PurgeMode::createTruncateMode()->getValue() === $this->purgeMode->getValue() + && $this->purger->getObjectManager()->getConnection()->getDriver() instanceof AbstractMySQLDriver + ); + + if ($truncateOrm) { + $connection = $this->purger->getObjectManager()->getConnection(); + + $connection->exec('SET FOREIGN_KEY_CHECKS = 0;'); + } + + $this->purger->purge(); + + if ($truncateOrm && isset($connection)) { + $connection->exec('SET FOREIGN_KEY_CHECKS = 1;'); + } + } + + private static function createPurger(ObjectManager $manager, ?PurgeMode $purgeMode): DoctrinePurgerInterface + { + if ($manager instanceof EntityManagerInterface) { + $purger = new DoctrineOrmPurger($manager); + + if (null !== $purgeMode) { + $purger->setPurgeMode($purgeMode->getValue()); + } + + return $purger; + } + + if ($manager instanceof DoctrinePhpCrDocumentManager) { + return new DoctrinePhpCrPurger($manager); + } + + if ($manager instanceof DoctrineMongoDocumentManager) { + return new DoctrineMongoDBPurger($manager); + } + + throw new InvalidArgumentException( + sprintf( + 'Cannot create a purger for ObjectManager of class %s', + get_class($manager) + ) + ); + } +} diff --git a/src/Bridge/Doctrine/Purger/Purger.php b/src/Bridge/Doctrine/Purger/Purger.php index da53aed7..dd5ef975 100644 --- a/src/Bridge/Doctrine/Purger/Purger.php +++ b/src/Bridge/Doctrine/Purger/Purger.php @@ -13,132 +13,33 @@ namespace Fidry\AliceDataFixtures\Bridge\Doctrine\Purger; -use Doctrine\Common\DataFixtures\Purger\MongoDBPurger as DoctrineMongoDBPurger; -use Doctrine\Common\DataFixtures\Purger\ORMPurger as DoctrineOrmPurger; -use Doctrine\Common\DataFixtures\Purger\PHPCRPurger as DoctrinePhpCrPurger; -use Doctrine\Common\DataFixtures\Purger\PurgerInterface as DoctrinePurgerInterface; use Doctrine\Common\Persistence\ObjectManager; -use Doctrine\DBAL\Driver\AbstractMySQLDriver; -use Doctrine\ODM\MongoDB\DocumentManager as DoctrineMongoDocumentManager; -use Doctrine\ODM\PHPCR\DocumentManager as DoctrinePhpCrDocumentManager; -use Doctrine\ORM\EntityManagerInterface; +use const E_USER_DEPRECATED; use Fidry\AliceDataFixtures\Persistence\PurgeMode; -use Fidry\AliceDataFixtures\Persistence\PurgerFactoryInterface; -use Fidry\AliceDataFixtures\Persistence\PurgerInterface; -use InvalidArgumentException; -use Nelmio\Alice\IsAServiceTrait; +use function trigger_error; /** - * Bridge for Doctrine purger. + * @deprecated Use ObjectManagerPurger instead * - * @author Vincent CHALAMON - * @final + * @see ObjectManagerPurger */ -/* final */ class Purger implements PurgerInterface, PurgerFactoryInterface +/* final */ class Purger extends ObjectManagerPurger { - use IsAServiceTrait; - - private $manager; - private $purgeMode; - private $purger; - - public function __construct(ObjectManager $manager, PurgeMode $purgeMode = null) - { - $this->manager = $manager; - $this->purgeMode = $purgeMode; - - $this->purger = static::createPurger($manager, $purgeMode); - } - - /** - * @inheritdoc - */ - public function create(PurgeMode $mode, PurgerInterface $purger = null): PurgerInterface - { - if (null === $purger) { - return new self($this->manager, $mode); - } - - if ($purger instanceof DoctrinePurgerInterface) { - $manager = $purger->getObjectManager(); - } elseif ($purger instanceof self) { - $manager = $purger->manager; - } else { - throw new InvalidArgumentException( - sprintf( - 'Expected purger to be either and instance of "%s" or "%s". Got "%s".', - DoctrinePurgerInterface::class, - __CLASS__, - get_class($purger) - ) - ); - } - - if (null === $manager) { - throw new InvalidArgumentException( - sprintf( - 'Expected purger "%s" to have an object manager, got "null" instead.', - get_class($purger) - ) - ); - } - - return new self($manager, $mode); - } - /** * @inheritdoc */ - public function purge() + public function __construct(ObjectManager $manager, PurgeMode $purgeMode = null) { - // Because MySQL rocks, you got to disable foreign key checks when doing a TRUNCATE unlike in for example - // PostgreSQL. This ideally should be done in the Purger of doctrine/data-fixtures but meanwhile we are doing - // it here. - // See the progress in https://github.com/doctrine/data-fixtures/pull/272 - $truncateOrm = ( - $this->purger instanceof DoctrineOrmPurger - && PurgeMode::createTruncateMode()->getValue() === $this->purgeMode->getValue() - && $this->purger->getObjectManager()->getConnection()->getDriver() instanceof AbstractMySQLDriver + @trigger_error( + sprintf( + '"%s" has been deprecated since v1.2.0. Use "%s" instead.', + self::class, + ObjectManagerPurger::class + ), + E_USER_DEPRECATED ); - if ($truncateOrm) { - $connection = $this->purger->getObjectManager()->getConnection(); - - $connection->exec('SET FOREIGN_KEY_CHECKS = 0;'); - } - - $this->purger->purge(); - - if ($truncateOrm && isset($connection)) { - $connection->exec('SET FOREIGN_KEY_CHECKS = 1;'); - } + parent::__construct($manager, $purgeMode); } - private static function createPurger(ObjectManager $manager, ?PurgeMode $purgeMode): DoctrinePurgerInterface - { - if ($manager instanceof EntityManagerInterface) { - $purger = new DoctrineOrmPurger($manager); - - if (null !== $purgeMode) { - $purger->setPurgeMode($purgeMode->getValue()); - } - - return $purger; - } - - if ($manager instanceof DoctrinePhpCrDocumentManager) { - return new DoctrinePhpCrPurger($manager); - } - - if ($manager instanceof DoctrineMongoDocumentManager) { - return new DoctrineMongoDBPurger($manager); - } - - throw new InvalidArgumentException( - sprintf( - 'Cannot create a purger for ObjectManager of class %s', - get_class($manager) - ) - ); - } } diff --git a/src/Bridge/Symfony/Resources/config/doctrine_mongodb_odm.xml b/src/Bridge/Symfony/Resources/config/doctrine_mongodb_odm.xml index 4068f490..98a52b88 100644 --- a/src/Bridge/Symfony/Resources/config/doctrine_mongodb_odm.xml +++ b/src/Bridge/Symfony/Resources/config/doctrine_mongodb_odm.xml @@ -52,6 +52,7 @@ + @@ -71,7 +72,7 @@ - + diff --git a/src/Bridge/Symfony/Resources/config/doctrine_orm.xml b/src/Bridge/Symfony/Resources/config/doctrine_orm.xml index b2906397..2289260a 100644 --- a/src/Bridge/Symfony/Resources/config/doctrine_orm.xml +++ b/src/Bridge/Symfony/Resources/config/doctrine_orm.xml @@ -52,6 +52,7 @@ + @@ -79,7 +80,7 @@ - + diff --git a/src/Bridge/Symfony/Resources/config/doctrine_phpcr_odm.xml b/src/Bridge/Symfony/Resources/config/doctrine_phpcr_odm.xml index 3b94e524..bdec5296 100644 --- a/src/Bridge/Symfony/Resources/config/doctrine_phpcr_odm.xml +++ b/src/Bridge/Symfony/Resources/config/doctrine_phpcr_odm.xml @@ -52,12 +52,14 @@ + + The service "%service_id%s" is deprecated and will be removed in future versions. Use "fidry_alice_data_fixtures.persistence.doctrine_phpcr.purger.purger_factory" instead. @@ -73,7 +75,7 @@ - + diff --git a/src/Persistence/PurgerInterface.php b/src/Persistence/PurgerInterface.php index bfe67204..c286633b 100644 --- a/src/Persistence/PurgerInterface.php +++ b/src/Persistence/PurgerInterface.php @@ -34,6 +34,8 @@ interface PurgerInterface /** * Purges the database before loading. Depending of the implementation, the purge may truncate the database or * remove only a part of the database data. + * + * @return void The typehint is gonna be enforced from 2.0.0 onwards */ public function purge(); } diff --git a/tests/Bridge/Doctrine/Persister/ObjectManagerPersisterTest.php b/tests/Bridge/Doctrine/Persister/ObjectManagerPersisterTest.php index 5c0eef5c..8d0ebf41 100644 --- a/tests/Bridge/Doctrine/Persister/ObjectManagerPersisterTest.php +++ b/tests/Bridge/Doctrine/Persister/ObjectManagerPersisterTest.php @@ -14,6 +14,7 @@ namespace Fidry\AliceDataFixtures\Bridge\Doctrine\Persister; use Doctrine\Common\DataFixtures\Purger\ORMPurger; +use Doctrine\Common\Persistence\ManagerRegistry; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\ORMException; use Doctrine\ORM\ORMInvalidArgumentException; @@ -25,6 +26,7 @@ use Fidry\AliceDataFixtures\Bridge\Doctrine\Entity\MappedSuperclassDummy; use Fidry\AliceDataFixtures\Exception\ObjectGeneratorPersisterException; use Fidry\AliceDataFixtures\Persistence\PersisterInterface; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use ReflectionClass; @@ -48,13 +50,23 @@ class ObjectManagerPersisterTest extends TestCase */ private $purger; + /** + * @var ManagerRegistry|MockObject + */ + private $managerRegistry; + /** * @inheritdoc */ public function setUp() { $this->entityManager = $GLOBALS['entity_manager']; - $this->persister = new ObjectManagerPersister($this->entityManager); + + $this->managerRegistry = $this->createMock(ManagerRegistry::class); + $this->managerRegistry->method('getManagerForClass')->willReturn($this->entityManager); + $this->managerRegistry->method('getManagers')->willReturn([$this->entityManager]); + + $this->persister = new ObjectManagerPersister($this->managerRegistry); $this->purger = new ORMPurger($this->entityManager); }