![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/mautic.corals.io/app/bundles/EmailBundle/Entity/ |
<?php namespace Mautic\EmailBundle\Entity; use Doctrine\Common\Collections\ArrayCollection; use Doctrine\Common\Collections\Collection; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Events; use Doctrine\ORM\Mapping as ORM; use Mautic\ApiBundle\Serializer\Driver\ApiMetadataDriver; use Mautic\AssetBundle\Entity\Asset; use Mautic\CoreBundle\Doctrine\Mapping\ClassMetadataBuilder; use Mautic\CoreBundle\Entity\DynamicContentEntityTrait; use Mautic\CoreBundle\Entity\FormEntity; use Mautic\CoreBundle\Entity\TranslationEntityInterface; use Mautic\CoreBundle\Entity\TranslationEntityTrait; use Mautic\CoreBundle\Entity\VariantEntityInterface; use Mautic\CoreBundle\Entity\VariantEntityTrait; use Mautic\CoreBundle\Helper\UrlHelper; use Mautic\CoreBundle\Validator\EntityEvent; use Mautic\EmailBundle\Validator\EmailLists; use Mautic\EmailBundle\Validator\EmailOrEmailTokenList; use Mautic\FormBundle\Entity\Form; use Mautic\LeadBundle\Entity\LeadList; use Mautic\PageBundle\Entity\Page; use Symfony\Component\Validator\Constraints\Callback; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Context\ExecutionContextInterface; use Symfony\Component\Validator\Mapping\ClassMetadata; class Email extends FormEntity implements VariantEntityInterface, TranslationEntityInterface { use VariantEntityTrait; use TranslationEntityTrait; use DynamicContentEntityTrait; /** * @var int */ private $id; /** * @var string */ private $name; /** * @var string|null */ private $description; /** * @var string|null */ private $subject; /** * @var bool|null */ private $useOwnerAsMailer; /** * @var string|null */ private $fromAddress; /** * @var string|null */ private $fromName; /** * @var string|null */ private $replyToAddress; /** * @var string|null */ private $bccAddress; /** * @var string|null */ private $template; /** * @var array */ private $content = []; /** * @var array */ private $utmTags = []; /** * @var string|null */ private $plainText; /** * @var string|null */ private $customHtml; /** * @var string|null */ private $emailType = 'template'; /** * @var \DateTimeInterface|null */ private $publishUp; /** * @var \DateTimeInterface|null */ private $publishDown; /** * @var bool|null */ private $publicPreview = false; /** * @var int */ private $readCount = 0; /** * @var int */ private $sentCount = 0; /** * @var int */ private $revision = 1; /** * @var \Mautic\CategoryBundle\Entity\Category|null **/ private $category; /** * @var ArrayCollection<\Mautic\LeadBundle\Entity\LeadList> */ private $lists; /** * @var ArrayCollection<\Mautic\LeadBundle\Entity\LeadList> */ private $excludedLists; /** * @var ArrayCollection<\Mautic\EmailBundle\Entity\Stat> */ private $stats; /** * @var int */ private $variantSentCount = 0; /** * @var int */ private $variantReadCount = 0; /** * @var Form|null */ private $unsubscribeForm; /** * @var Page|null */ private $preferenceCenter; /** * @var ArrayCollection<\Mautic\AssetBundle\Entity\Asset> */ private $assetAttachments; /** * Used to identify the page for the builder. */ private $sessionId; /** * @var array */ private $headers = []; /** * @var int */ private $pendingCount = 0; /** * @var int */ private $queuedCount = 0; private bool $isCloned = false; /** * In some use cases, we need to get the original email ID after it's been cloned. * * @var int */ private $clonedId; public function __clone() { $this->isCloned = true; $this->clonedId = $this->id; $this->id = null; $this->sentCount = 0; $this->readCount = 0; $this->revision = 0; $this->variantSentCount = 0; $this->variantReadCount = 0; $this->variantStartDate = null; $this->emailType = null; $this->sessionId = 'new_'.hash('sha1', uniqid(mt_rand())); $this->plainText = null; $this->publishUp = null; $this->publishDown = null; $this->clearTranslations(); $this->clearVariants(); $this->clearStats(); parent::__clone(); } public function __construct() { $this->lists = new ArrayCollection(); $this->excludedLists = new ArrayCollection(); $this->stats = new ArrayCollection(); $this->translationChildren = new ArrayCollection(); $this->variantChildren = new ArrayCollection(); $this->assetAttachments = new ArrayCollection(); $this->setDateAdded(new \DateTime()); $this->setDateModified(new \DateTime()); } public function clearStats(): void { $this->stats = new ArrayCollection(); } public static function loadMetadata(ORM\ClassMetadata $metadata): void { $builder = new ClassMetadataBuilder($metadata); $builder->setTable('emails') ->setCustomRepositoryClass(EmailRepository::class) ->addLifecycleEvent('cleanUrlsInContent', Events::preUpdate) ->addLifecycleEvent('cleanUrlsInContent', Events::prePersist); $builder->addIdColumns(); $builder->addNullableField('subject', Types::TEXT); $builder->addNullableField('fromAddress', Types::STRING, 'from_address'); $builder->addNullableField('fromName', Types::STRING, 'from_name'); $builder->addNullableField('replyToAddress', Types::STRING, 'reply_to_address'); $builder->addNullableField('bccAddress', Types::STRING, 'bcc_address'); $builder->addNullableField('useOwnerAsMailer', Types::BOOLEAN, 'use_owner_as_mailer'); $builder->addNullableField('template', Types::STRING); $builder->addNullableField('content', Types::ARRAY); $builder->addNullableField('utmTags', Types::ARRAY, 'utm_tags'); $builder->addNullableField('plainText', Types::TEXT, 'plain_text'); $builder->addNullableField('customHtml', Types::TEXT, 'custom_html'); $builder->addNullableField('emailType', Types::TEXT, 'email_type'); $builder->addPublishDates(); $builder->addNamedField('readCount', Types::INTEGER, 'read_count'); $builder->addNamedField('sentCount', Types::INTEGER, 'sent_count'); $builder->addNamedField('variantSentCount', Types::INTEGER, 'variant_sent_count'); $builder->addNamedField('variantReadCount', Types::INTEGER, 'variant_read_count'); $builder->addField('revision', Types::INTEGER); $builder->addCategory(); $builder->createManyToMany('lists', LeadList::class) ->setJoinTable('email_list_xref') ->setIndexBy('id') ->addInverseJoinColumn('leadlist_id', 'id', false, false, 'CASCADE') ->addJoinColumn('email_id', 'id', false, false, 'CASCADE') ->fetchExtraLazy() ->build(); $builder->createManyToMany('excludedLists', LeadList::class) ->setJoinTable('email_list_excluded') ->setIndexBy('id') ->addInverseJoinColumn('leadlist_id', 'id', false, false, 'CASCADE') ->addJoinColumn('email_id', 'id', false, false, 'CASCADE') ->fetchExtraLazy() ->build(); $builder->createOneToMany('stats', 'Stat') ->setIndexBy('id') ->mappedBy('email') ->cascadePersist() ->fetchExtraLazy() ->build(); self::addTranslationMetadata($builder, self::class); self::addVariantMetadata($builder, self::class); self::addDynamicContentMetadata($builder); $builder->createManyToOne('unsubscribeForm', Form::class) ->addJoinColumn('unsubscribeform_id', 'id', true, false, 'SET NULL') ->build(); $builder->createManyToOne('preferenceCenter', Page::class) ->addJoinColumn('preference_center_id', 'id', true, false, 'SET NULL') ->build(); $builder->createManyToMany('assetAttachments', Asset::class) ->setJoinTable('email_assets_xref') ->addInverseJoinColumn('asset_id', 'id', false, false, 'CASCADE') ->addJoinColumn('email_id', 'id', false, false, 'CASCADE') ->fetchExtraLazy() ->build(); $builder->addField('headers', Types::JSON); $builder->addNullableField('publicPreview', Types::BOOLEAN, 'public_preview'); } public static function loadValidatorMetadata(ClassMetadata $metadata): void { $metadata->addPropertyConstraint( 'name', new NotBlank( [ 'message' => 'mautic.core.name.required', ] ) ); $metadata->addPropertyConstraint( 'subject', new NotBlank( [ 'message' => 'mautic.core.subject.required', ] ) ); $metadata->addPropertyConstraint( 'fromAddress', new EmailOrEmailTokenList(), ); $metadata->addPropertyConstraint( 'replyToAddress', new \Symfony\Component\Validator\Constraints\Email( [ 'message' => 'mautic.core.email.required', ] ) ); $metadata->addPropertyConstraint( 'bccAddress', new \Symfony\Component\Validator\Constraints\Email( [ 'message' => 'mautic.core.email.required', ] ) ); $metadata->addConstraint(new EmailLists()); $metadata->addConstraint(new EntityEvent()); $metadata->addConstraint(new Callback([ 'callback' => function (Email $email, ExecutionContextInterface $context): void { if ($email->isVariant()) { // Get a summation of weights $parent = $email->getVariantParent(); $children = $parent ? $parent->getVariantChildren() : $email->getVariantChildren(); $total = 0; foreach ($children as $child) { $settings = $child->getVariantSettings(); $total += (int) $settings['weight']; } if ($total > 100) { $context->buildViolation('mautic.core.variant_weights_invalid') ->atPath('variantSettings[weight]') ->addViolation(); } } }, ])); } /** * Prepares the metadata for API usage. */ public static function loadApiMetadata(ApiMetadataDriver $metadata): void { $metadata->setGroupPrefix('email') ->addListProperties( [ 'id', 'name', 'subject', 'language', 'category', ] ) ->addProperties( [ 'fromAddress', 'fromName', 'replyToAddress', 'bccAddress', 'useOwnerAsMailer', 'utmTags', 'customHtml', 'plainText', 'template', 'emailType', 'publishUp', 'publishDown', 'publicPreview', 'readCount', 'sentCount', 'revision', 'assetAttachments', 'variantStartDate', 'variantSentCount', 'variantReadCount', 'variantParent', 'variantChildren', 'translationParent', 'translationChildren', 'unsubscribeForm', 'dynamicContent', 'lists', 'headers', ] ) ->build(); } protected function isChanged($prop, $val) { $getter = 'get'.ucfirst($prop); $current = $this->$getter(); if ('variantParent' == $prop || 'translationParent' == $prop || 'category' == $prop || 'list' == $prop) { $currentId = ($current) ? $current->getId() : ''; $newId = ($val) ? $val->getId() : null; if ($currentId != $newId) { $this->changes[$prop] = [$currentId, $newId]; } } else { parent::isChanged($prop, $val); } } /** * @return mixed */ public function getName() { return $this->name; } /** * @return $this */ public function setName($name) { $this->name = $name; return $this; } /** * @return mixed */ public function getDescription() { return $this->description; } /** * @param mixed $description * * @return Email */ public function setDescription($description) { $this->description = $description; return $this; } public function setId(int $id): Email { $this->id = $id; return $this; } /** * @return int|null */ public function getId() { return $this->id; } /** * @return mixed */ public function getCategory() { return $this->category; } /** * @return $this */ public function setCategory($category) { $this->isChanged('category', $category); $this->category = $category; return $this; } /** * @return array */ public function getContent() { return $this->content; } /** * @return $this */ public function setContent($content) { $this->isChanged('content', $content); $this->content = $content; return $this; } /** * @return array */ public function getUtmTags() { return $this->utmTags; } /** * @param array $utmTags */ public function setUtmTags($utmTags) { $this->isChanged('utmTags', $utmTags); $this->utmTags = $utmTags; return $this; } /** * @return mixed */ public function getReadCount($includeVariants = false) { return ($includeVariants) ? $this->getAccumulativeVariantCount('getReadCount') : $this->readCount; } /** * @return $this */ public function setReadCount($readCount) { $this->readCount = $readCount; return $this; } public function getIsClone(): bool { return $this->isCloned; } /** * @return mixed */ public function getRevision() { return $this->revision; } /** * @return $this */ public function setRevision($revision) { $this->revision = $revision; return $this; } /** * @return mixed */ public function getSessionId() { return $this->sessionId; } /** * @return $this */ public function setSessionId($sessionId) { $this->sessionId = $sessionId; return $this; } /** * @return mixed */ public function getSubject() { return $this->subject; } /** * @return $this */ public function setSubject($subject) { $this->isChanged('subject', $subject); $this->subject = $subject; return $this; } /** * @return ?bool */ public function getUseOwnerAsMailer() { return $this->useOwnerAsMailer; } /** * @param bool $useOwnerAsMailer * * @return $this */ public function setUseOwnerAsMailer($useOwnerAsMailer) { $this->useOwnerAsMailer = $useOwnerAsMailer; return $this; } /** * @return mixed */ public function getFromAddress() { return $this->fromAddress; } /** * @param mixed $fromAddress * * @return Email */ public function setFromAddress($fromAddress) { $this->isChanged('fromAddress', $fromAddress); $this->fromAddress = $fromAddress; return $this; } /** * @return mixed */ public function getFromName() { return $this->fromName; } /** * @param mixed $fromName * * @return Email */ public function setFromName($fromName) { $this->isChanged('fromName', $fromName); $this->fromName = $fromName; return $this; } /** * @return mixed */ public function getReplyToAddress() { return $this->replyToAddress; } /** * @param mixed $replyToAddress * * @return Email */ public function setReplyToAddress($replyToAddress) { $this->isChanged('replyToAddress', $replyToAddress); $this->replyToAddress = $replyToAddress; return $this; } /** * @return mixed */ public function getBccAddress() { return $this->bccAddress; } /** * @param mixed $bccAddress * * @return Email */ public function setBccAddress($bccAddress) { $this->isChanged('bccAddress', $bccAddress); $this->bccAddress = $bccAddress; return $this; } /** * @return mixed */ public function getTemplate() { return $this->template; } /** * @return $this */ public function setTemplate($template) { $this->isChanged('template', $template); $this->template = $template; return $this; } /** * @return mixed */ public function getPublishDown() { return $this->publishDown; } /** * @return $this */ public function setPublishDown($publishDown) { $this->isChanged('publishDown', $publishDown); $this->publishDown = $publishDown; return $this; } /** * @return mixed */ public function getPublishUp() { return $this->publishUp; } /** * @return $this */ public function setPublishUp($publishUp) { $this->isChanged('publishUp', $publishUp); $this->publishUp = $publishUp; return $this; } /** * @param bool $includeVariants * * @return mixed */ public function getSentCount($includeVariants = false) { return ($includeVariants) ? $this->getAccumulativeVariantCount('getSentCount') : $this->sentCount; } /** * @return $this */ public function setSentCount($sentCount) { $this->sentCount = $sentCount; return $this; } /** * @return mixed */ public function getVariantSentCount($includeVariants = false) { return ($includeVariants) ? $this->getAccumulativeVariantCount('getVariantSentCount') : $this->variantSentCount; } /** * @return $this */ public function setVariantSentCount($variantSentCount) { $this->variantSentCount = $variantSentCount; return $this; } /** * @return ArrayCollection<int, \Mautic\LeadBundle\Entity\LeadList> */ public function getLists() { return $this->lists; } /** * Add list. * * @return Email */ public function addList(LeadList $list) { $this->listsChangedAdd('lists', $list->getId()); $this->lists[] = $list; return $this; } /** * Set the lists for this translation. */ public function setLists(array $lists = []) { $lists = new ArrayCollection($lists); $this->listsChangedSet('lists', $this->getListKeys($lists)); $this->lists = $lists; return $this; } /** * Remove list. */ public function removeList(LeadList $list): void { $this->listsChangedRemove('lists', $list->getId()); $this->lists->removeElement($list); } /** * @return Collection<int, \Mautic\LeadBundle\Entity\LeadList> */ public function getExcludedLists(): Collection { return $this->excludedLists; } public function addExcludedList(LeadList $excludedList): void { $this->listsChangedAdd('excludedLists', $excludedList->getId()); $this->excludedLists->add($excludedList); } public function removeExcludedList(LeadList $excludedList): void { $this->listsChangedRemove('excludedLists', $excludedList->getId()); $this->excludedLists->removeElement($excludedList); } /** * @return mixed */ public function getPlainText() { return $this->plainText; } /** * @return $this */ public function setPlainText($plainText) { $this->plainText = $plainText; return $this; } /** * @return mixed */ public function getVariantReadCount() { return $this->variantReadCount; } /** * @return $this */ public function setVariantReadCount($variantReadCount) { $this->variantReadCount = $variantReadCount; return $this; } /** * @return mixed */ public function getStats() { return $this->stats; } /** * @return mixed */ public function getCustomHtml() { return $this->customHtml; } /** * @return $this */ public function setCustomHtml($customHtml) { $this->customHtml = $customHtml; return $this; } /** * @return mixed */ public function getUnsubscribeForm() { return $this->unsubscribeForm; } /** * @return $this */ public function setUnsubscribeForm(Form $unsubscribeForm = null) { $this->unsubscribeForm = $unsubscribeForm; return $this; } /** * @return mixed */ public function getPreferenceCenter() { return $this->preferenceCenter; } /** * @return $this */ public function setPreferenceCenter(Page $preferenceCenter = null) { $this->preferenceCenter = $preferenceCenter; return $this; } /** * @return mixed */ public function getEmailType() { return $this->emailType; } /** * @param mixed $emailType * * @return Email */ public function setEmailType($emailType) { $this->emailType = $emailType; return $this; } /** * Add asset. * * @return Email */ public function addAssetAttachment(Asset $asset) { $this->assetAttachments[] = $asset; return $this; } /** * Remove asset. */ public function removeAssetAttachment(Asset $asset): void { $this->assetAttachments->removeElement($asset); } /** * Get assetAttachments. * * @return Collection */ public function getAssetAttachments() { return $this->assetAttachments; } /** * @return array */ public function getHeaders() { return $this->headers; } /** * @param array $headers * * @return Email */ public function setHeaders($headers) { $this->headers = $headers; return $this; } /** * Lifecycle callback to clean URLs in the content. */ public function cleanUrlsInContent(): void { if (is_string($this->plainText)) { $this->decodeAmpersands($this->plainText); } if (is_string($this->customHtml)) { $this->decodeAmpersands($this->customHtml); } } /** * Check all links in content and decode ampersands. */ private function decodeAmpersands(string &$content): void { if (preg_match_all('/((https?|ftps?):\/\/)([a-zA-Z0-9-\.{}]*[a-zA-Z0-9=}]*)(\??)([^\s\"\]]+)?/i', $content, $matches)) { foreach ($matches[0] as $url) { $content = str_replace($url, UrlHelper::decodeAmpersands($url), $content); } } } /** * Calculate Read Percentage for each Email. * * @return int */ public function getReadPercentage($includevariants = false) { if ($this->getSentCount($includevariants) > 0) { return round($this->getReadCount($includevariants) / $this->getSentCount($includevariants) * 100, 2); } else { return 0; } } /** * @return bool */ public function getPublicPreview() { return $this->publicPreview; } /** * @return bool */ public function isPublicPreview() { return $this->publicPreview; } /** * @param bool $publicPreview * * @return $this */ public function setPublicPreview($publicPreview) { $this->isChanged('publicPreview', $publicPreview); $this->publicPreview = $publicPreview; return $this; } /** * @param int $count * * @return $this */ public function setQueuedCount($count) { $this->queuedCount = $count; return $this; } /** * @return int */ public function getQueuedCount() { return $this->queuedCount; } /** * @param int $count * * @return $this */ public function setPendingCount($count) { $this->pendingCount = $count; return $this; } /** * @return int */ public function getPendingCount() { return $this->pendingCount; } public function getClonedId(): ?int { return $this->clonedId; } public function isBackgroundSending(): bool { return $this->isPublished() && !empty($this->getPublishUp()) && ($this->getPublishUp() < new \DateTime()); } private function listsChangedAdd(string $property, ?int $id): void { $this->initListChanges($property); $this->changes[$property][1] = array_unique(array_merge($this->changes[$property][1], [$id])); } private function listsChangedRemove(string $property, ?int $id): void { $this->initListChanges($property); $this->changes[$property][1] = array_diff($this->changes[$property][1], [$id]); } /** * @param mixed[] $ids */ private function listsChangedSet(string $property, array $ids): void { $this->initListChanges($property); $this->changes[$property][1] = $ids; } private function initListChanges(string $property): void { if (!isset($this->changes[$property])) { $list = $this->$property; $current = $this->getListKeys($list); $this->changes[$property] = [$current, $current]; } } /** * @param iterable<mixed> $list * * @return mixed[] */ private function getListKeys(iterable $list): array { $keys = []; foreach ($list as $key => $value) { $keys[] = $key; } return $keys; } }