/** * Get the number of leads this email will be sent to * * @param Email $email * @param mixed $listId Leads for a specific lead list * @param bool $countOnly If true, return count otherwise array of leads * @param int $limit Max number of leads to retrieve * @param bool $includeVariants If false, emails sent to a variant will not be included * * @return int|array */ public function getPendingLeads(Email $email, $listId = null, $countOnly = false, $limit = null, $includeVariants = true) { if ($includeVariants && $email->isVariant()) { $parent = $email->getVariantParent(); if ($parent) { // $email is a variant of another $ids[] = $parent->getId(); $children = $parent->getVariantChildren(); $variantIds = $children->getKeys(); // Remove $email from the array $key = array_search($email->getId(), $variantIds); unset($variantIds[$key]); } else { $children = $email->getVariantChildren(); $variantIds = $children->getKeys(); } } else { $variantIds = null; } $total = $this->getRepository()->getEmailPendingLeads($email->getId(), $variantIds, $listId, $countOnly, $limit); return $total; }
/** * {@inheritdoc} * * @param Email $entity * @param $unlock * * @return mixed */ public function saveEntity($entity, $unlock = true) { $now = new \DateTime(); $type = $entity->getEmailType(); if (empty($type)) { // Just in case JS failed $entity->setEmailType('template'); } // Ensure that list emails are published if ($entity->getEmailType() == 'list') { $entity->setIsPublished(true); $entity->setPublishDown(null); $entity->setPublishUp(null); } //set the author for new pages if (!$entity->isNew()) { //increase the revision $revision = $entity->getRevision(); $revision++; $entity->setRevision($revision); //reset the variant hit and start date if there are any changes $changes = $entity->getChanges(); if ($entity->isVariant() && !empty($changes) && empty($this->inConversion)) { $entity->setVariantSentCount(0); $entity->setVariantStartDate($now); } } parent::saveEntity($entity, $unlock); //also reset variants if applicable due to changes if (!empty($changes) && empty($this->inConversion)) { $parent = $entity->getVariantParent(); $children = !empty($parent) ? $parent->getVariantChildren() : $entity->getVariantChildren(); $variants = array(); if (!empty($parent)) { $parent->setVariantSentCount(0); $parent->setVariantStartDate($now); $variants[] = $parent; } if (count($children)) { foreach ($children as $child) { $child->setVariantSentCount(0); $child->setVariantStartDate($now); $variants[] = $child; } } //if the parent was changed, then that parent/children must also be reset if (isset($changes['variantParent'])) { $parent = $this->getEntity($changes['variantParent'][0]); if (!empty($parent)) { $parent->setVariantSentCount(0); $parent->setVariantStartDate($now); $variants[] = $parent; $children = $parent->getVariantChildren(); if (count($children)) { foreach ($children as $child) { $child->setVariantSentCount(0); $child->setVariantStartDate($now); $variants[] = $child; } } } } if (!empty($variants)) { $this->saveEntities($variants, false); } } }
/** * Gets template, stats, weights, etc for an email in preparation to be sent * * @param Email $email * @param bool $includeVariants * * @return array */ public function &getEmailSettings(Email $email, $includeVariants = true) { if (empty($this->emailSettings[$email->getId()])) { //used to house slots so they don't have to be fetched over and over for same template // BC for Mautic v1 templates $slots = []; if ($template = $email->getTemplate()) { $slots[$template] = $this->themeHelper->getTheme($template)->getSlots('email'); } //store the settings of all the variants in order to properly disperse the emails //set the parent's settings $emailSettings = [$email->getId() => ['template' => $email->getTemplate(), 'slots' => $slots, 'sentCount' => $email->getSentCount(), 'variantCount' => $email->getVariantSentCount(), 'isVariant' => null !== $email->getVariantStartDate(), 'entity' => $email, 'translations' => $email->getTranslations(true), 'languages' => ['default' => $email->getId()]]]; if ($emailSettings[$email->getId()]['translations']) { // Add in the sent counts for translations of this email /** @var Email $translation */ foreach ($emailSettings[$email->getId()]['translations'] as $translation) { if ($translation->isPublished()) { $emailSettings[$email->getId()]['sentCount'] += $translation->getSentCount(); $emailSettings[$email->getId()]['variantCount'] += $translation->getVariantSentCount(); // Prevent empty key due to misconfiguration - pretty much ignored if (!($language = $translation->getLanguage())) { $language = 'unknown'; } $core = $this->getTranslationLocaleCore($language); if (!isset($emailSettings[$email->getId()]['languages'][$core])) { $emailSettings[$email->getId()]['languages'][$core] = []; } $emailSettings[$email->getId()]['languages'][$core][$language] = $translation->getId(); } } } if ($includeVariants && $email->isVariant()) { //get a list of variants for A/B testing $childrenVariant = $email->getVariantChildren(); if (count($childrenVariant)) { $variantWeight = 0; $totalSent = $emailSettings[$email->getId()]['variantCount']; foreach ($childrenVariant as $id => $child) { if ($child->isPublished()) { $useSlots = []; if ($template = $child->getTemplate()) { if (isset($slots[$template])) { $useSlots = $slots[$template]; } else { $slots[$template] = $this->themeHelper->getTheme($template)->getSlots('email'); $useSlots = $slots[$template]; } } $variantSettings = $child->getVariantSettings(); $emailSettings[$child->getId()] = ['template' => $child->getTemplate(), 'slots' => $useSlots, 'sentCount' => $child->getSentCount(), 'variantCount' => $child->getVariantSentCount(), 'isVariant' => null !== $email->getVariantStartDate(), 'weight' => $variantSettings['weight'] / 100, 'entity' => $child, 'translations' => $child->getTranslations(true), 'languages' => ['default' => $child->getId()]]; $variantWeight += $variantSettings['weight']; if ($emailSettings[$child->getId()]['translations']) { // Add in the sent counts for translations of this email /** @var Email $translation */ foreach ($emailSettings[$child->getId()]['translations'] as $translation) { if ($translation->isPublished()) { $emailSettings[$child->getId()]['sentCount'] += $translation->getSentCount(); $emailSettings[$child->getId()]['variantCount'] += $translation->getVariantSentCount(); // Prevent empty key due to misconfiguration - pretty much ignored if (!($language = $translation->getLanguage())) { $language = 'unknown'; } $core = $this->getTranslationLocaleCore($language); if (!isset($emailSettings[$child->getId()]['languages'][$core])) { $emailSettings[$child->getId()]['languages'][$core] = []; } $emailSettings[$child->getId()]['languages'][$core][$language] = $translation->getId(); } } } $totalSent += $emailSettings[$child->getId()]['variantCount']; } } //set parent weight $emailSettings[$email->getId()]['weight'] = (100 - $variantWeight) / 100; } else { $emailSettings[$email->getId()]['weight'] = 1; } } $this->emailSettings[$email->getId()] = $emailSettings; } if ($includeVariants && $email->isVariant()) { //now find what percentage of current leads should receive the variants if (!isset($totalSent)) { $totalSent = 0; foreach ($this->emailSettings[$email->getId()] as $eid => $details) { $totalSent += $details['variantCount']; } } foreach ($this->emailSettings[$email->getId()] as $eid => &$details) { // Determine the deficit for email ordering if ($totalSent) { $details['weight_deficit'] = $details['weight'] - $details['variantCount'] / $totalSent; $details['send_weight'] = $details['weight'] - $details['variantCount'] / $totalSent + $details['weight']; } else { $details['weight_deficit'] = $details['weight']; $details['send_weight'] = $details['weight']; } } // Reorder according to send_weight so that campaigns which currently send one at a time alternate uasort($this->emailSettings[$email->getId()], function ($a, $b) { if ($a['weight_deficit'] === $b['weight_deficit']) { if ($a['variantCount'] === $b['variantCount']) { return 0; } // if weight is the same - sort by least number sent return $a['variantCount'] < $b['variantCount'] ? -1 : 1; } // sort by the one with the greatest deficit first return $a['weight_deficit'] > $b['weight_deficit'] ? -1 : 1; }); } return $this->emailSettings[$email->getId()]; }
/** * {@inheritDoc} */ public function isVariant($isChild = false) { $this->__initializer__ && $this->__initializer__->__invoke($this, 'isVariant', array($isChild)); return parent::isVariant($isChild); }