EM based table prefixing

This commit is contained in:
Rix Beck
2020-04-01 19:58:46 +02:00
parent 56e071e253
commit a9d59cd6fe
3 changed files with 91 additions and 30 deletions

View File

@@ -4,33 +4,38 @@ declare(strict_types=1);
namespace Bolt\Doctrine;
use Bolt\Common\Str;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Symfony\Bridge\Doctrine\ManagerRegistry;
class TablePrefix
{
private $tablePrefix;
use TablePrefixTrait;
public function __construct(string $tablePrefix)
public function __construct($tablePrefixes, ManagerRegistry $managerRegistry)
{
$this->tablePrefix = Str::ensureEndsWith($tablePrefix, '_');
$this->setTablePrefixes($tablePrefixes, $managerRegistry);
}
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs): void
{
$classMetadata = $eventArgs->getClassMetadata();
if ($tablePrefix = $this->getTablePrefix($eventArgs->getEntityManager())) {
$classMetadata = $eventArgs->getClassMetadata();
if (! $classMetadata->isInheritanceTypeSingleTable() || $classMetadata->getName() === $classMetadata->rootEntityName) {
$classMetadata->setPrimaryTable([
'name' => $this->tablePrefix . $classMetadata->getTableName(),
]);
}
if (!$classMetadata->isInheritanceTypeSingleTable()
|| $classMetadata->getName() === $classMetadata->rootEntityName) {
$classMetadata->setPrimaryTable(
[
'name' => $tablePrefix.$classMetadata->getTableName(),
]
);
}
foreach ($classMetadata->getAssociationMappings() as $fieldName => $mapping) {
if ($mapping['type'] === ClassMetadataInfo::MANY_TO_MANY && $mapping['isOwningSide']) {
$mappedTableName = $mapping['joinTable']['name'];
$classMetadata->associationMappings[$fieldName]['joinTable']['name'] = $this->tablePrefix . $mappedTableName;
foreach ($classMetadata->getAssociationMappings() as $fieldName => $mapping) {
if ($mapping['type'] === ClassMetadataInfo::MANY_TO_MANY && $mapping['isOwningSide']) {
$mappedTableName = $mapping['joinTable']['name'];
$classMetadata->associationMappings[$fieldName]['joinTable']['name'] = $tablePrefix.$mappedTableName;
}
}
}
}

View File

@@ -0,0 +1,45 @@
<?php
/**
* @author Rix Beck <rix@neologik.hu>
*/
namespace Bolt\Doctrine;
use Bolt\Common\Str;
use Doctrine\Persistence\ObjectManager;
use Symfony\Bridge\Doctrine\ManagerRegistry;
trait TablePrefixTrait
{
private $tablePrefixes = [];
protected function setTablePrefix(ObjectManager $manager, string $prefix)
{
$key = spl_object_hash($manager);
$this->tablePrefixes[$key] = Str::ensureEndsWith($prefix, '_');
return $this;
}
protected function setTablePrefixes($tablePrefixes, ManagerRegistry $managerRegistry)
{
$prefixes = (array)$tablePrefixes;
$this->registry = $managerRegistry;
foreach ($prefixes as $em => $tablePrefix) {
$manager = $managerRegistry->getManager(is_int($em) ? 'default' : $em);
if ($manager) {
$this->setTablePrefix($manager, $tablePrefix);
}
}
return $this;
}
protected function getTablePrefix(ObjectManager $manager)
{
$key = spl_object_hash($manager);
return $this->tablePrefixes[$key] ?? '';
}
}

View File

@@ -4,14 +4,17 @@ declare(strict_types=1);
namespace Bolt\Event\Subscriber;
use Bolt\Common\Str;
use Bolt\Doctrine\TablePrefixTrait;
use Carbon\Carbon;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Doctrine\ManagerRegistry;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\KernelEvents;
class TimedPublishSubscriber implements EventSubscriberInterface
{
use TablePrefixTrait;
public const PRIORITY = 30;
/** @var EntityManagerInterface */
@@ -20,10 +23,22 @@ class TimedPublishSubscriber implements EventSubscriberInterface
/** @var string */
private $tablePrefix;
public function __construct(string $tablePrefix, EntityManagerInterface $entityManager)
public function __construct($tablePrefixes, ManagerRegistry $managerRegistry)
{
$this->entityManager = $entityManager;
$this->tablePrefix = Str::ensureEndsWith($tablePrefix, '_');
$this->entityManager = $managerRegistry->getManager('default');
$this->tablePrefix = $this
->setTablePrefixes($tablePrefixes, $managerRegistry)
->getTablePrefix($this->entityManager);
}
/**
* Return the events to subscribe to.
*/
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => [['onKernelRequest', self::PRIORITY]], // Right after route is matched
];
}
/**
@@ -36,8 +51,14 @@ class TimedPublishSubscriber implements EventSubscriberInterface
// Publish timed Content records when 'publish_at' has passed and Depublish published Content
// records when 'depublish_at' has passed. Note: Placeholders in DBAL don't work for tablenames.
$queryPublish = sprintf('update %scontent SET status = "published", published_at = :now WHERE status = "timed" AND published_at < :now', $this->tablePrefix);
$queryDepublish = sprintf('update %scontent SET status = "held", depublished_at = :now WHERE status = "published" AND depublished_at < :now', $this->tablePrefix);
$queryPublish = sprintf(
'update %scontent SET status = "published", published_at = :now WHERE status = "timed" AND published_at < :now',
$this->tablePrefix
);
$queryDepublish = sprintf(
'update %scontent SET status = "held", depublished_at = :now WHERE status = "published" AND depublished_at < :now',
$this->tablePrefix
);
try {
$conn->executeUpdate($queryPublish, [':now' => $now]);
@@ -46,14 +67,4 @@ class TimedPublishSubscriber implements EventSubscriberInterface
// Fail silently, output user-friendly exception elsewhere.
}
}
/**
* Return the events to subscribe to.
*/
public static function getSubscribedEvents(): array
{
return [
KernelEvents::REQUEST => [['onKernelRequest', self::PRIORITY]], // Right after route is matched
];
}
}