['dynamicContent:read'], 'swagger_definition_name' => 'Read', 'api_included' => ['category', 'translationChildren'], ], denormalizationContext: [ 'groups' => ['dynamicContent:write'], 'swagger_definition_name' => 'Write', ] )] /** * @use TranslationEntityTrait * @use VariantEntityTrait */ class DynamicContent extends FormEntity implements VariantEntityInterface, TranslationEntityInterface, UuidInterface { use TranslationEntityTrait; use VariantEntityTrait; use FiltersEntityTrait; use UuidTrait; use ProjectTrait; public const ENTITY_NAME = 'dynamic_content'; /** * @var int */ #[Groups(['dynamicContent:read'])] private $id; #[Groups(['dynamicContent:read', 'dynamicContent:write'])] private ?string $name = null; #[Groups(['dynamicContent:read', 'dynamicContent:write'])] private string $type = TypeList::HTML; #[Groups(['dynamicContent:read', 'dynamicContent:write'])] private ?string $description = null; #[Groups(['dynamicContent:read', 'dynamicContent:write'])] private ?Category $category = null; /** * @var \DateTimeInterface */ #[Groups(['dynamicContent:read', 'dynamicContent:write'])] private $publishUp; /** * @var \DateTimeInterface */ #[Groups(['dynamicContent:read', 'dynamicContent:write'])] private $publishDown; /** * @var string|null */ #[Groups(['dynamicContent:read', 'dynamicContent:write'])] private $content; /** * @var array|null */ #[Groups(['dynamicContent:read', 'dynamicContent:write'])] private $utmTags = []; /** * @var int */ #[Groups(['dynamicContent:read'])] private $sentCount = 0; /** * @var ArrayCollection */ #[Groups(['dynamicContent:read'])] private $stats; /** * @var bool */ #[Groups(['dynamicContent:read', 'dynamicContent:write'])] private $isCampaignBased = true; /** * @var string|null */ #[Groups(['dynamicContent:read', 'dynamicContent:write'])] private $slotName; public function __construct() { $this->stats = new ArrayCollection(); $this->translationChildren = new ArrayCollection(); $this->variantChildren = new ArrayCollection(); $this->initializeProjects(); } public function __clone() { $this->id = null; $this->sentCount = 0; $this->stats = new ArrayCollection(); $this->translationChildren = new ArrayCollection(); $this->variantChildren = new ArrayCollection(); parent::__clone(); } public function clearStats(): void { $this->stats = new ArrayCollection(); } public static function loadMetadata(ORM\ClassMetadata $metadata): void { $builder = new ClassMetadataBuilder($metadata); $builder->setTable('dynamic_content') ->addIndex(['is_campaign_based'], 'is_campaign_based_index') ->addIndex(['slot_name'], 'slot_name_index') ->setCustomRepositoryClass(DynamicContentRepository::class) ->addLifecycleEvent('cleanSlotName', Events::prePersist) ->addLifecycleEvent('cleanSlotName', Events::preUpdate); $builder->addIdColumns(); $builder->addCategory(); $builder->addField( 'type', Types::STRING, [ 'length' => 10, 'default' => TypeList::HTML, ] ); $builder->addPublishDates(); $builder->createField('sentCount', 'integer') ->columnName('sent_count') ->build(); $builder->createField('content', 'text') ->columnName('content') ->nullable() ->build(); $builder->createField('utmTags', Types::JSON) ->columnName('utm_tags') ->nullable() ->build(); $builder->createOneToMany('stats', 'Stat') ->setIndexBy('id') ->mappedBy('dynamicContent') ->cascadePersist() ->fetchExtraLazy() ->build(); self::addTranslationMetadata($builder, self::class); self::addVariantMetadata($builder, self::class); self::addFiltersMetadata($builder); $builder->createField('isCampaignBased', 'boolean') ->columnName('is_campaign_based') ->option('default', 1) ->build(); $builder->createField('slotName', 'string') ->columnName('slot_name') ->nullable() ->build(); static::addUuidField($builder); self::addProjectsField($builder, 'dynamic_content_projects_xref', 'dynamic_content_id'); } /** * @throws \Symfony\Component\Validator\Exception\ConstraintDefinitionException * @throws \Symfony\Component\Validator\Exception\InvalidOptionsException * @throws \Symfony\Component\Validator\Exception\MissingOptionsException */ public static function loadValidatorMetaData(ClassMetadata $metadata): void { $metadata->addPropertyConstraint('name', new NotBlank(['message' => 'mautic.core.name.required'])); $metadata->addPropertyConstraint('content', new NoNesting()); $metadata->addPropertyConstraint('type', new NotBlank(['message' => 'mautic.core.type.required'])); $metadata->addPropertyConstraint('type', new Choice(['choices' => (new TypeList())->getChoices()])); $metadata->addConstraint(new SlotNameType()); $metadata->addConstraint(new Callback( function (self $dwc, ExecutionContextInterface $context): void { if (!$dwc->getIsCampaignBased()) { $validator = $context->getValidator(); $violations = $validator->validate( $dwc->getSlotName(), [ new NotBlank( [ 'message' => 'mautic.dynamicContent.slot_name.notblank', ] ), ] ); foreach ($violations as $violation) { $context->buildViolation($violation->getMessage()) ->atPath('slotName') ->addViolation(); } $violations = $validator->validate( $dwc->getFilters(), [ new Count( [ 'minMessage' => 'mautic.dynamicContent.filter.options.empty', 'min' => 1, ] ), ] ); foreach ($violations as $violation) { $context->buildViolation($violation->getMessage()) ->atPath('filters') ->addViolation(); } } }, )); } public static function loadApiMetadata(ApiMetadataDriver $metadata): void { $metadata->setGroupPrefix('dwc') ->addListProperties([ 'id', 'name', 'category', 'type', ]) ->addProperties([ 'publishUp', 'publishDown', 'sentCount', 'variantParent', 'variantChildren', 'content', 'utmTags', 'filters', 'isCampaignBased', 'slotName', ]) ->setMaxDepth(1, 'variantParent') ->setMaxDepth(1, 'variantChildren') ->build(); self::addProjectsInLoadApiMetadata($metadata, 'dwc'); } protected function isChanged($prop, $val) { $getter = 'get'.ucfirst($prop); $current = $this->$getter(); if ('variantParent' == $prop || 'translationParent' == $prop || 'category' == $prop) { $currentId = ($current) ? $current->getId() : ''; $newId = ($val) ? $val->getId() : null; if ($currentId != $newId) { $this->changes[$prop] = [$currentId, $newId]; } } else { parent::isChanged($prop, $val); } } /** * @return int|null */ public function getId() { return $this->id; } /** * @return string */ public function getName() { return $this->name; } /** * @param string $name * * @return $this */ public function setName($name) { $this->isChanged('name', $name); $this->name = $name; return $this; } /** * @return string */ public function getDescription() { return $this->description; } /** * @param string $description * * @return $this */ public function setDescription($description) { $this->description = $description; return $this; } public function setType(string $type): void { $type = strtolower($type); $this->isChanged('type', $type); $this->type = $type; } public function getType(): string { return $this->type; } /** * @return Category */ public function getCategory() { return $this->category; } /** * @param Category $category * * @return $this */ public function setCategory($category) { $this->isChanged('category', $category); $this->category = $category; return $this; } /** * @return \DateTimeInterface */ public function getPublishUp() { return $this->publishUp; } /** * @param \DateTime $publishUp * * @return $this */ public function setPublishUp($publishUp) { $this->isChanged('publishUp', $publishUp); $this->publishUp = $publishUp; return $this; } /** * @return \DateTimeInterface */ public function getPublishDown() { return $this->publishDown; } /** * @param \DateTime $publishDown * * @return $this */ public function setPublishDown($publishDown) { $this->isChanged('publishDown', $publishDown); $this->publishDown = $publishDown; return $this; } /** * @return string */ public function getContent() { return $this->content; } /** * @param string $content * * @return $this */ public function setContent($content) { $this->isChanged('content', $content); $this->content = $content; return $this; } /** * @param bool $includeVariants * * @return mixed */ public function getSentCount($includeVariants = false) { return $includeVariants ? $this->getAccumulativeTranslationCount('getSentCount') : $this->sentCount; } /** * @return $this */ public function setSentCount($sentCount) { $this->sentCount = $sentCount; return $this; } /** * @return ArrayCollection */ public function getStats() { return $this->stats; } /** * @return bool */ public function getIsCampaignBased() { return $this->isCampaignBased; } /** * @param bool $isCampaignBased * * @return $this */ public function setIsCampaignBased($isCampaignBased) { $this->isChanged('isCampaignBased', $isCampaignBased); $this->isCampaignBased = $isCampaignBased; return $this; } /** * @return string */ public function getSlotName() { return $this->slotName; } /** * @param string $slotName * * @return $this */ public function setSlotName($slotName) { $this->isChanged('slotName', $slotName); $this->slotName = $slotName; return $this; } /** * Lifecycle callback to clear the slot name if is_campaign is true. */ public function cleanSlotName(): void { if ($this->getIsCampaignBased()) { $this->setSlotName(''); } } /** * @return DynamicContent */ public function setUtmTags(array $utmTags) { $this->isChanged('utmTags', $utmTags); $this->utmTags = $utmTags; return $this; } /** * @return array */ public function getUtmTags() { return $this->utmTags; } }