Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 85 additions & 0 deletions src/Bridge/Doctrine/Persister/ManagerRegistryPersister.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

/*
* This file is part of the Fidry\AliceDataFixtures package.
*
* (c) Théo FIDRY <theo.fidry@gmail.com>
*
* 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)];
}
}
2 changes: 1 addition & 1 deletion src/Bridge/Doctrine/Persister/ObjectManagerPersister.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
use Fidry\AliceDataFixtures\Persistence\PersisterInterface;
use Nelmio\Alice\IsAServiceTrait;

class ObjectManagerPersister implements PersisterInterface
/* final */ class ObjectManagerPersister implements PersisterInterface
{
use IsAServiceTrait;

Expand Down
74 changes: 74 additions & 0 deletions src/Bridge/Doctrine/Purger/ManagerRegistryPurger.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?php

/*
* This file is part of the Fidry\AliceDataFixtures package.
*
* (c) Théo FIDRY <theo.fidry@gmail.com>
*
* 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()
);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This part here makes the assumption that data from all managers (and hence databases) should be purged every time.

IMHO this seems counter intuitive when running bin/console hautelook:fixtures:load --manager=foo. I certainly wouldn't expect the database of manager bar be also purged.

Looking at the problem from a wider perspective, perhaps it would be more sensible to remove the --manager option and instead create a purger for only those managers which contain at least a single entity with fixtures defined for it?

Copy link
Owner Author

@theofidry theofidry Aug 29, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If that could be done I guess it would be less potential side-effects indeed... Either that or --manager should restrict the purgers as well

}

/**
* @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();
}
}
}
144 changes: 144 additions & 0 deletions src/Bridge/Doctrine/Purger/ObjectManagerPurger.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
<?php

/*
* This file is part of the Fidry\AliceDataFixtures package.
*
* (c) Théo FIDRY <theo.fidry@gmail.com>
*
* 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 <vincentchalamon@gmail.com>
* @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)
)
);
}
}
Loading