Skip to content

Instantly share code, notes, and snippets.

@heathdutton
Last active June 20, 2018 21:15
Show Gist options
  • Save heathdutton/5ed0edc0a3dd7dd77eb478a918868812 to your computer and use it in GitHub Desktop.
Save heathdutton/5ed0edc0a3dd7dd77eb478a918868812 to your computer and use it in GitHub Desktop.
[Bug] Symfony Master/Slave support is broken #5969 - Prevent conflict with #6021
diff --git a/app/bundles/CampaignBundle/Entity/CampaignRepository.php b/app/bundles/CampaignBundle/Entity/CampaignRepository.php
index c463a0bad1..c041bb4760 100644
--- a/app/bundles/CampaignBundle/Entity/CampaignRepository.php
+++ b/app/bundles/CampaignBundle/Entity/CampaignRepository.php
@@ -21,6 +21,7 @@
class CampaignRepository extends CommonRepository
{
use ContactLimiterTrait;
+ use SlaveConnectionTrait;
/**
* {@inheritdoc}
@@ -539,7 +540,7 @@ public function getCampaignOrphanLeads($id, array $lists, $args = [])
*/
public function getPendingEventContactCount($campaignId, array $pendingEvents, ContactLimiter $limiter)
{
- $q = $this->getEntityManager()->getConnection()->createQueryBuilder();
+ $q = $this->getSlaveConnection($limiter)->createQueryBuilder();
$q->select('count(cl.lead_id) as lead_count')
->from(MAUTIC_TABLE_PREFIX.'campaign_leads', 'cl')
@@ -584,7 +585,7 @@ public function getPendingEventContactCount($campaignId, array $pendingEvents, C
*/
public function getPendingContactIds($campaignId, ContactLimiter $limiter)
{
- $q = $this->getEntityManager()->getConnection()->createQueryBuilder();
+ $q = $this->getSlaveConnection($limiter)->createQueryBuilder();
$q->select('cl.lead_id')
->from(MAUTIC_TABLE_PREFIX.'campaign_leads', 'cl')
@@ -600,7 +601,7 @@ public function getPendingContactIds($campaignId, ContactLimiter $limiter)
$this->updateQueryFromContactLimiter('cl', $q, $limiter);
// Only leads that have not started the campaign
- $sq = $this->getEntityManager()->getConnection()->createQueryBuilder();
+ $sq = $this->getSlaveConnection($limiter)->createQueryBuilder();
$sq->select('null')
->from(MAUTIC_TABLE_PREFIX.'campaign_lead_event_log', 'e')
->where(
@@ -639,7 +640,7 @@ public function getPendingContactIds($campaignId, ContactLimiter $limiter)
*/
public function getCampaignLeadCount($campaignId, $leadId = null, $pendingEvents = [], $dateRangeValues = null)
{
- $q = $this->getEntityManager()->getConnection()->createQueryBuilder();
+ $q = $this->getSlaveConnection()->createQueryBuilder();
$q->select('count(cl.lead_id) as lead_count')
->from(MAUTIC_TABLE_PREFIX.'campaign_leads', 'cl')
@@ -658,7 +659,7 @@ public function getCampaignLeadCount($campaignId, $leadId = null, $pendingEvents
}
if (count($pendingEvents) > 0) {
- $sq = $this->getEntityManager()->getConnection()->createQueryBuilder();
+ $sq = $this->getSlaveConnection()->createQueryBuilder();
$sq->select('null')
->from(MAUTIC_TABLE_PREFIX.'campaign_lead_event_log', 'e')
->where(
@@ -690,7 +691,7 @@ public function getCampaignLeadCount($campaignId, $leadId = null, $pendingEvents
*/
public function getCampaignLeads($campaignId, $start = 0, $limit = false, $select = ['cl.lead_id'])
{
- $q = $this->getEntityManager()->getConnection()->createQueryBuilder();
+ $q = $this->getSlaveConnection()->createQueryBuilder();
$q->select($select)
->from(MAUTIC_TABLE_PREFIX.'campaign_leads', 'cl')
diff --git a/app/bundles/CampaignBundle/Entity/LeadEventLogRepository.php b/app/bundles/CampaignBundle/Entity/LeadEventLogRepository.php
index 15d0fde35d..6bc6c285e9 100644
--- a/app/bundles/CampaignBundle/Entity/LeadEventLogRepository.php
+++ b/app/bundles/CampaignBundle/Entity/LeadEventLogRepository.php
@@ -25,6 +25,7 @@ class LeadEventLogRepository extends CommonRepository
{
use TimelineTrait;
use ContactLimiterTrait;
+ use SlaveConnectionTrait;
public function getEntities(array $args = [])
{
@@ -217,7 +218,7 @@ public function getUpcomingEvents(array $options = null)
*/
public function getCampaignLogCounts($campaignId, $excludeScheduled = false, $excludeNegative = true, $dateRangeValues = null)
{
- $q = $this->_em->getConnection()->createQueryBuilder()
+ $q = $this->getSlaveConnection()->createQueryBuilder()
->from(MAUTIC_TABLE_PREFIX.'campaign_lead_event_log', 'o')
->leftJoin(
'o',
@@ -251,7 +252,7 @@ public function getCampaignLogCounts($campaignId, $excludeScheduled = false, $ex
}
// Exclude failed events
- $failedSq = $this->_em->getConnection()->createQueryBuilder();
+ $failedSq = $this->getSlaveConnection()->createQueryBuilder();
$failedSq->select('null')
->from(MAUTIC_TABLE_PREFIX.'campaign_lead_event_failed_log', 'fe')
->where(
@@ -350,10 +351,10 @@ public function updateLead($fromLeadId, $toLeadId)
*/
public function getChartQuery($options)
{
- $chartQuery = new ChartQuery($this->getEntityManager()->getConnection(), $options['dateFrom'], $options['dateTo']);
+ $chartQuery = new ChartQuery($this->getSlaveConnection(), $options['dateFrom'], $options['dateTo']);
// Load points for selected period
- $query = $this->_em->getConnection()->createQueryBuilder();
+ $query = $this->getSlaveConnection()->createQueryBuilder();
$query->select('ll.id, ll.date_triggered')
->from(MAUTIC_TABLE_PREFIX.'campaign_lead_event_log', 'll')
->join('ll', MAUTIC_TABLE_PREFIX.'campaign_events', 'e', 'e.id = ll.event_id');
@@ -398,6 +399,7 @@ public function getChartQuery($options)
*/
public function getScheduled($eventId, \DateTime $now, ContactLimiter $limiter)
{
+ $this->getSlaveConnection($limiter);
$q = $this->createQueryBuilder('o');
$q->select('o, e, c')
@@ -430,6 +432,7 @@ public function getScheduled($eventId, \DateTime $now, ContactLimiter $limiter)
*/
public function getScheduledByIds(array $ids)
{
+ $this->getSlaveConnection();
$q = $this->createQueryBuilder('o');
$q->select('o, e, c')
@@ -459,7 +462,7 @@ public function getScheduledCounts($campaignId, \DateTime $date, ContactLimiter
$now = clone $date;
$now->setTimezone(new \DateTimeZone('UTC'));
- $q = $this->getEntityManager()->getConnection()->createQueryBuilder();
+ $q = $this->getSlaveConnection($limiter)->createQueryBuilder();
$expr = $q->expr()->andX(
$q->expr()->eq('l.campaign_id', ':campaignId'),
@@ -498,7 +501,7 @@ public function getScheduledCounts($campaignId, \DateTime $date, ContactLimiter
*/
public function getDatesExecuted($eventId, array $contactIds)
{
- $qb = $this->getEntityManager()->getConnection()->createQueryBuilder();
+ $qb = $this->getSlaveConnection()->createQueryBuilder();
$qb->select('log.lead_id, log.date_triggered')
->from(MAUTIC_TABLE_PREFIX.'campaign_lead_event_log', 'log')
->where(
diff --git a/app/bundles/CampaignBundle/Entity/LeadRepository.php b/app/bundles/CampaignBundle/Entity/LeadRepository.php
index dfea8a886c..885b8329a4 100644
--- a/app/bundles/CampaignBundle/Entity/LeadRepository.php
+++ b/app/bundles/CampaignBundle/Entity/LeadRepository.php
@@ -20,6 +20,7 @@
class LeadRepository extends CommonRepository
{
use ContactLimiterTrait;
+ use SlaveConnectionTrait;
/**
* Get the details of leads added to a campaign.
@@ -204,7 +205,7 @@ public function checkLeadInCampaigns($lead, $options = [])
public function getInactiveContacts($campaignId, $decisionId, $parentDecisionId, ContactLimiter $limiter)
{
// Main query
- $q = $this->getEntityManager()->getConnection()->createQueryBuilder();
+ $q = $this->getSlaveConnection($limiter)->createQueryBuilder();
$q->select('l.lead_id, l.date_added')
->from(MAUTIC_TABLE_PREFIX.'campaign_leads', 'l')
->where($q->expr()->eq('l.campaign_id', ':campaignId'))
@@ -218,7 +219,7 @@ public function getInactiveContacts($campaignId, $decisionId, $parentDecisionId,
$this->updateQueryFromContactLimiter('l', $q, $limiter);
// Limit to events that have not been executed or scheduled yet
- $eventQb = $this->getEntityManager()->getConnection()->createQueryBuilder();
+ $eventQb = $this->getSlaveConnection($limiter)->createQueryBuilder();
$eventQb->select('null')
->from(MAUTIC_TABLE_PREFIX.'campaign_lead_event_log', 'log')
->where(
@@ -234,7 +235,7 @@ public function getInactiveContacts($campaignId, $decisionId, $parentDecisionId,
if ($parentDecisionId) {
// Limit to events that have no grandparent or whose grandparent has already been executed
- $grandparentQb = $this->getEntityManager()->getConnection()->createQueryBuilder();
+ $grandparentQb = $this->getSlaveConnection($limiter)->createQueryBuilder();
$grandparentQb->select('null')
->from(MAUTIC_TABLE_PREFIX.'campaign_lead_event_log', 'grandparent_log')
->where(
@@ -276,7 +277,7 @@ public function getInactiveContactCount($campaignId, array $decisionIds, Contact
foreach ($decisionIds as $decisionId) {
// Main query
- $q = $this->getEntityManager()->getConnection()->createQueryBuilder();
+ $q = $this->getSlaveConnection()->createQueryBuilder();
$q->select('count(*)')
->from(MAUTIC_TABLE_PREFIX.'campaign_leads', 'l')
->where($q->expr()->eq('l.campaign_id', ':campaignId'))
@@ -288,7 +289,7 @@ public function getInactiveContactCount($campaignId, array $decisionIds, Contact
$this->updateQueryFromContactLimiter('l', $q, $limiter, true);
// Limit to events that have not been executed or scheduled yet
- $eventQb = $this->getEntityManager()->getConnection()->createQueryBuilder();
+ $eventQb = $this->getSlaveConnection($limiter)->createQueryBuilder();
$eventQb->select('null')
->from(MAUTIC_TABLE_PREFIX.'campaign_lead_event_log', 'log')
->where(
diff --git a/app/bundles/CampaignBundle/Entity/SlaveConnectionTrait.php b/app/bundles/CampaignBundle/Entity/SlaveConnectionTrait.php
new file mode 100644
index 0000000000..234c7e43df
--- /dev/null
+++ b/app/bundles/CampaignBundle/Entity/SlaveConnectionTrait.php
@@ -0,0 +1,48 @@
+<?php
+
+/*
+ * @copyright 2018 Mautic Contributors. All rights reserved
+ * @author Mautic, Inc.
+ *
+ * @link https://mautic.org
+ *
+ * @license GNU/GPLv3 http://www.gnu.org/licenses/gpl-3.0.html
+ */
+
+namespace Mautic\CampaignBundle\Entity;
+
+use Doctrine\DBAL\Connection;
+use Doctrine\DBAL\Connections\MasterSlaveConnection;
+use Mautic\CampaignBundle\Executioner\ContactFinder\Limiter\ContactLimiter;
+
+/**
+ * Trait SlaveConnectionTrait.
+ */
+trait SlaveConnectionTrait
+{
+ /**
+ * Get a connection, preferring a slave connection if available and prudent.
+ *
+ * If a query is being executed with a limiter with specific contacts
+ * then this could be a real-time request being handled so we should avoid forcing a slave connection.
+ *
+ * @param ContactLimiter|null $limiter
+ *
+ * @return Connection
+ */
+ private function getSlaveConnection(ContactLimiter $limiter = null)
+ {
+ /** @var Connection $connection */
+ $connection = $this->getEntityManager()->getConnection();
+ if ($connection instanceof MasterSlaveConnection) {
+ if (
+ !$limiter
+ || !($limiter->getContactId() || $limiter->getContactIdList())
+ ) {
+ $connection->connect('slave');
+ }
+ }
+
+ return $connection;
+ }
+}
diff --git a/app/bundles/CoreBundle/Doctrine/Helper/TableSchemaHelper.php b/app/bundles/CoreBundle/Doctrine/Helper/TableSchemaHelper.php
index afbc659b49..c358f828c0 100644
--- a/app/bundles/CoreBundle/Doctrine/Helper/TableSchemaHelper.php
+++ b/app/bundles/CoreBundle/Doctrine/Helper/TableSchemaHelper.php
@@ -68,7 +68,14 @@ public function __construct(Connection $db, $prefix, ColumnSchemaHelper $columnH
$this->sm = $db->getSchemaManager();
$this->prefix = $prefix;
$this->columnHelper = $columnHelper;
- $this->schema = new Schema([], [], $this->sm->createSchemaConfig());
+ if ($db instanceof \Doctrine\DBAL\Connections\MasterSlaveConnection) {
+ $params = $db->getParams();
+ $schemaConfig = new \Doctrine\DBAL\Schema\SchemaConfig();
+ $schemaConfig->setName($params['master']['dbname']);
+ $this->schema = new Schema([], [], $schemaConfig);
+ } else {
+ $this->schema = new Schema([], [], $this->sm->createSchemaConfig());
+ }
}
/**
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment