Initial commit: CloudOps infrastructure platform

This commit is contained in:
root
2026-04-09 19:58:57 +02:00
commit 1166a52f26
7762 changed files with 839452 additions and 0 deletions

View File

@@ -0,0 +1,68 @@
<?php
namespace Mautic\LeadBundle\Event;
use Mautic\CategoryBundle\Entity\Category;
use Mautic\LeadBundle\Entity\Lead;
use Symfony\Contracts\EventDispatcher\Event;
class CategoryChangeEvent extends Event
{
private ?Lead $lead = null;
/**
* @var Lead[]|null
*/
private ?array $leads = null;
/**
* @param Lead|Lead[] $leads
*/
public function __construct(
Lead|array $leads,
private Category $category,
private bool $added = true,
) {
if (is_array($leads)) {
$this->leads = $leads;
} else {
$this->lead = $leads;
}
}
/**
* @return Lead
*/
public function getLead()
{
return $this->lead;
}
/**
* Returns batch array of leads.
*
* @return array
*/
public function getLeads()
{
return $this->leads;
}
/**
* @return Category
*/
public function getCategory()
{
return $this->category;
}
public function wasAdded(): bool
{
return $this->added;
}
public function wasRemoved(): bool
{
return !$this->added;
}
}

View File

@@ -0,0 +1,67 @@
<?php
namespace Mautic\LeadBundle\Event;
use Mautic\LeadBundle\Entity\DoNotContact;
use Mautic\LeadBundle\Entity\Lead;
use Symfony\Contracts\EventDispatcher\Event;
class ChannelSubscriptionChange extends Event
{
/**
* @param string $channel
*/
public function __construct(
private Lead $lead,
private $channel,
private int $oldStatus,
private int $newStatus,
) {
}
/**
* @return Lead
*/
public function getLead()
{
return $this->lead;
}
/**
* @return string
*/
public function getChannel()
{
return $this->channel;
}
public function getOldStatus(): int
{
return $this->oldStatus;
}
public function getOldStatusVerb(): string
{
return $this->getDncReasonVerb($this->oldStatus);
}
public function getNewStatus(): int
{
return $this->newStatus;
}
public function getNewStatusVerb(): string
{
return $this->getDncReasonVerb($this->newStatus);
}
private function getDncReasonVerb($reason): string
{
return match (true) {
DoNotContact::IS_CONTACTABLE === $reason => 'contactable',
DoNotContact::BOUNCED === $reason => 'bounced',
DoNotContact::MANUAL === $reason => 'manual',
default => 'unsubscribed',
};
}
}

View File

@@ -0,0 +1,7 @@
<?php
namespace Mautic\LeadBundle\Event;
class CompanyBuildSearchEvent extends LeadBuildSearchEvent
{
}

View File

@@ -0,0 +1,50 @@
<?php
namespace Mautic\LeadBundle\Event;
use Mautic\CoreBundle\Event\CommonEvent;
use Mautic\LeadBundle\Entity\Company;
class CompanyEvent extends CommonEvent
{
/**
* @param bool $isNew
* @param int $score
*/
public function __construct(
Company $company,
$isNew = false,
protected $score = 0,
) {
$this->entity = $company;
$this->isNew = $isNew;
}
/**
* Returns the Company entity.
*
* @return Company
*/
public function getCompany()
{
return $this->entity;
}
/**
* Sets the Company entity.
*/
public function setCompany(Company $company): void
{
$this->entity = $company;
}
public function changeScore($score): void
{
$this->score = $score;
}
public function getScore()
{
return $this->score;
}
}

View File

@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Mautic\LeadBundle\Entity\Company;
use Symfony\Contracts\EventDispatcher\Event;
final class CompanyMergeEvent extends Event
{
public function __construct(
private Company $victor,
private Company $loser,
) {
}
/**
* Returns the victor (loser merges into the victor).
*/
public function getVictor(): Company
{
return $this->victor;
}
/**
* Returns the loser (loser merges into the victor).
*/
public function getLoser(): Company
{
return $this->loser;
}
}

View File

@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Symfony\Contracts\EventDispatcher\Event;
class ContactExportEvent extends Event
{
/**
* @param array<string|int, int|string|array<string, mixed>> $args
*/
public function __construct(
private array $args,
private string $object,
) {
}
/**
* @return array<string, string|array<string, mixed>>
*/
public function getArgs(): array
{
return $this->args;
}
public function getObject(): string
{
return $this->object;
}
}

View File

@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Mautic\LeadBundle\Entity\ContactExportScheduler;
use Symfony\Contracts\EventDispatcher\Event;
class ContactExportSchedulerEvent extends Event
{
private string $filePath;
public function __construct(
private ContactExportScheduler $contactExportScheduler,
) {
}
public function getContactExportScheduler(): ContactExportScheduler
{
return $this->contactExportScheduler;
}
public function getFilePath(): string
{
return $this->filePath;
}
public function setFilePath(string $filePath): void
{
$this->filePath = $filePath;
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace Mautic\LeadBundle\Event;
use Mautic\LeadBundle\Entity\Lead;
use Symfony\Contracts\EventDispatcher\Event;
class ContactIdentificationEvent extends Event
{
private ?Lead $identifiedContact = null;
/**
* @var string
*/
private $identifiedByChannel;
public function __construct(
private array $clickthrough,
) {
}
/**
* @return array
*/
public function getClickthrough()
{
return $this->clickthrough;
}
/**
* @param string $channel
*/
public function setIdentifiedContact(Lead $contact, $channel): void
{
$this->identifiedContact = $contact;
$this->identifiedByChannel = $channel;
$this->stopPropagation();
}
/**
* @return string
*/
public function getIdentifier()
{
return $this->identifiedByChannel;
}
/**
* @return Lead
*/
public function getIdentifiedContact()
{
return $this->identifiedContact;
}
}

View File

@@ -0,0 +1,60 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Mautic\LeadBundle\Entity\DoNotContact as DNC;
use Mautic\LeadBundle\Entity\Lead;
use Symfony\Contracts\EventDispatcher\Event;
final class DoNotContactAddEvent extends Event
{
public const ADD_DONOT_CONTACT = 'mautic.lead.add_donot_contact';
public function __construct(
private Lead $lead,
private string $channel,
private string $comments = '',
private int $reason = DNC::BOUNCED,
private bool $persist = true,
private bool $checkCurrentStatus = true,
private bool $override = true,
) {
}
public function getLead(): Lead
{
return $this->lead;
}
public function getChannel(): string
{
return $this->channel;
}
public function getComments(): string
{
return $this->comments;
}
public function getReason(): int
{
return $this->reason;
}
public function isPersist(): bool
{
return $this->persist;
}
public function isCheckCurrentStatus(): bool
{
return $this->checkCurrentStatus;
}
public function isOverride(): bool
{
return $this->override;
}
}

View File

@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Mautic\LeadBundle\Entity\Lead;
use Symfony\Contracts\EventDispatcher\Event;
final class DoNotContactRemoveEvent extends Event
{
public const REMOVE_DONOT_CONTACT = 'mautic.lead.remove_donot_contact';
public function __construct(
private Lead $lead,
private string $channel,
private bool $persist = true,
) {
}
public function getLead(): Lead
{
return $this->lead;
}
public function getChannel(): string
{
return $this->channel;
}
public function getPersist(): bool
{
return $this->persist;
}
}

View File

@@ -0,0 +1,70 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Symfony\Contracts\EventDispatcher\Event;
/**
* Event that collects operators for a specific field.
*/
final class FieldOperatorsEvent extends Event
{
/**
* $allOperators example:
* [
* '=' => [
* 'label' => 'equals',
* 'expr' => 'eq',
* 'negate_expr' => 'neq',
* ],
* '!=' => [
* 'label' => 'not equal',
* 'expr' => 'neq',
* 'negate_expr' => 'eq',
* ],
* ];.
*
* $defaultOperators example:
* [
* 'equals' => '=',
* 'not equal' => '!='
* ]
*
* @param array<string, string> $operators
* @param array<string,array<string,string>> $allOperators
*/
public function __construct(
private string $type,
private string $field,
private array $allOperators,
private array $operators,
) {
}
/**
* @return array<string,string>
*/
public function getOperators(): array
{
return $this->operators;
}
public function getField(): string
{
return $this->field;
}
public function getType(): string
{
return $this->type;
}
public function addOperator(string $operator): void
{
if (isset($this->allOperators[$operator])) {
$this->operators[$this->allOperators[$operator]['label']] = $operator;
}
}
}

View File

@@ -0,0 +1,89 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Mautic\LeadBundle\Segment\OperatorOptions;
use Symfony\Component\Form\FormInterface;
use Symfony\Contracts\EventDispatcher\Event;
final class FormAdjustmentEvent extends Event
{
/**
* @param FormInterface<mixed> $form
* @param mixed[] $fieldDetails
*/
public function __construct(
private FormInterface $form,
private string $fieldAlias,
private string $fieldObject,
private string $operator,
private array $fieldDetails,
) {
}
/**
* @return FormInterface<mixed>
*/
public function getForm(): FormInterface
{
return $this->form;
}
public function getFieldAlias(): string
{
return $this->fieldAlias;
}
public function getFieldObject(): string
{
return $this->fieldObject;
}
public function getOperator(): string
{
return $this->operator;
}
public function operatorIsOneOf(string ...$operators): bool
{
return in_array($this->getOperator(), $operators);
}
public function fieldTypeIsOneOf(string ...$fieldTypes): bool
{
return in_array($this->getFieldType(), $fieldTypes);
}
public function getFieldType(): string
{
return $this->fieldDetails['properties']['type'];
}
/**
* @return mixed[]
*/
public function getFieldDetails(): array
{
return $this->fieldDetails;
}
/**
* @return mixed[]
*/
public function getFieldChoices(): array
{
return $this->fieldDetails['properties']['list'] ?? [];
}
public function filterShouldBeDisabled(): bool
{
return $this->operatorIsOneOf(OperatorOptions::EMPTY, OperatorOptions::NOT_EMPTY);
}
public function filterShouldBeRequired(): bool
{
return !$this->operatorIsOneOf(OperatorOptions::EMPTY, OperatorOptions::NOT_EMPTY);
}
}

View File

@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Symfony\Contracts\EventDispatcher\Event;
final class GetStatDataEvent extends Event
{
/**
* @var array<string,mixed[]>
*/
private array $results = [];
/**
* @param mixed[] $data
*/
public function addResult(array $data): void
{
$this->results = $data;
}
/**
* @return mixed[]
*/
public function getResults(): array
{
return $this->results;
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace Mautic\LeadBundle\Event;
use Mautic\CoreBundle\Event\CommonEvent;
use Mautic\LeadBundle\Entity\Import;
class ImportEvent extends CommonEvent
{
/**
* @param bool $isNew
*/
public function __construct(Import $entity, $isNew)
{
$this->entity = $entity;
$this->isNew = $isNew;
}
/**
* Returns the Import entity.
*
* @return Import
*/
public function getEntity()
{
return $this->entity;
}
}

View File

@@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Mautic\CoreBundle\Event\CommonEvent;
final class ImportInitEvent extends CommonEvent
{
public bool $objectSupported = false;
public ?string $objectSingular = null;
public ?string $objectName = null; // Object name for humans. Will go through translator.
public ?string $activeLink = null;
public ?string $indexRoute = null;
public array $indexRouteParams = [];
public function __construct(
public string $routeObjectName,
) {
}
public function setIndexRoute(?string $indexRoute, array $routeParams = []): void
{
$this->indexRoute = $indexRoute;
$this->indexRouteParams = $routeParams;
}
/**
* Check if the import is for said route object and notes if the object exist.
*/
public function importIsForRouteObject(string $routeObject): bool
{
if ($this->routeObjectName === $routeObject) {
$this->objectSupported = true;
return true;
}
return false;
}
}

View File

@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Mautic\CoreBundle\Event\CommonEvent;
final class ImportMappingEvent extends CommonEvent
{
public bool $objectSupported = false;
public array $fields = [];
public function __construct(
public string $routeObjectName,
) {
}
/**
* Check if the import is for said route object and notes if the object exist.
*/
public function importIsForRouteObject(string $routeObject): bool
{
if ($this->routeObjectName === $routeObject) {
$this->objectSupported = true;
return true;
}
return false;
}
}

View File

@@ -0,0 +1,61 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Mautic\CoreBundle\Event\CommonEvent;
use Mautic\LeadBundle\Entity\Import;
use Mautic\LeadBundle\Entity\LeadEventLog;
final class ImportProcessEvent extends CommonEvent
{
private ?bool $wasMerged = null;
/**
* @var array<string>
*/
private array $warnings = [];
public function __construct(
public Import $import,
public LeadEventLog $eventLog,
public array $rowData,
) {
}
public function setWasMerged(bool $wasMerged): void
{
$this->wasMerged = $wasMerged;
}
/**
* @throws \UnexpectedValueException
*/
public function wasMerged(): bool
{
if (null === $this->wasMerged) {
throw new \UnexpectedValueException("Import failed as {$this->import->getObject()} object is missing import handler.");
}
return $this->wasMerged;
}
public function importIsForObject(string $object): bool
{
return $this->import->getObject() === $object;
}
/**
* @return array<string>
*/
public function getWarnings(): array
{
return $this->warnings;
}
public function addWarning(string $warning): void
{
$this->warnings[] = $warning;
}
}

View File

@@ -0,0 +1,128 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Symfony\Component\Form\FormInterface;
use Symfony\Contracts\EventDispatcher\Event;
class ImportValidateEvent extends Event
{
private bool $skipIfExists = false;
private ?int $ownerId = null;
private ?int $list = null;
/**
* @var mixed[]
*/
private array $matchedFields = [];
/**
* @var mixed[]
*/
private array $tags = [];
/**
* @param FormInterface<mixed> $form
*/
public function __construct(
private string $routeObjectName,
private FormInterface $form,
) {
}
/**
* @return FormInterface<mixed>
*/
public function getForm(): FormInterface
{
return $this->form;
}
/**
* Check if the form we're validating has errors.
*/
public function hasErrors(): bool
{
return (bool) count($this->form->getErrors());
}
/**
* Check if the import is for said route object and notes if the object exist.
*/
public function importIsForRouteObject(string $routeObject): bool
{
return $this->getRouteObjectName() === $routeObject;
}
public function getRouteObjectName(): string
{
return $this->routeObjectName;
}
/**
* Set the matchedFields in the event.
*
* @param mixed[] $matchedFields
*/
public function setMatchedFields(array $matchedFields): void
{
$this->matchedFields = $matchedFields;
}
public function getSkipIfExists(): bool
{
return $this->skipIfExists;
}
public function setSkipIfExists(bool $skipIfExists): void
{
$this->skipIfExists = $skipIfExists;
}
/**
* @return mixed[]
*/
public function getMatchedFields(): array
{
return $this->matchedFields;
}
public function setOwnerId(?int $ownerId = null): void
{
$this->ownerId = $ownerId;
}
public function getOwnerId(): ?int
{
return $this->ownerId;
}
public function setList(?int $list = null): void
{
$this->list = $list;
}
public function getList(): ?int
{
return $this->list;
}
/**
* @param mixed[] $tags
*/
public function setTags(array $tags = []): void
{
$this->tags = $tags;
}
/**
* @return mixed[]
*/
public function getTags(): array
{
return $this->tags;
}
}

View File

@@ -0,0 +1,153 @@
<?php
namespace Mautic\LeadBundle\Event;
use Doctrine\DBAL\Query\QueryBuilder;
use Mautic\CoreBundle\Event\CommonEvent;
class LeadBuildSearchEvent extends CommonEvent
{
protected string $subQuery;
protected bool $isSearchDone;
protected bool $returnParameters;
protected bool $strict;
protected array $parameters;
/**
* @param string $string
* @param string $command
* @param string $alias
*/
public function __construct(
protected $string,
protected $command,
protected $alias,
protected bool $negate,
protected QueryBuilder $queryBuilder,
) {
$this->subQuery = '';
$this->isSearchDone = false;
$this->strict = false;
$this->returnParameters = false;
$this->parameters = [];
}
/**
* @return string
*/
public function getString()
{
return $this->string;
}
/**
* @return string
*/
public function getCommand()
{
return $this->command;
}
/**
* @return string
*/
public function getAlias()
{
return $this->alias;
}
public function isNegation(): bool
{
return $this->negate;
}
/**
* @return QueryBuilder
*/
public function getQueryBuilder()
{
return $this->queryBuilder;
}
/**
* @param bool $status
*/
public function setSearchStatus($status): void
{
$this->isSearchDone = $status;
}
/**
* @param string $query
*/
public function setSubQuery($query): void
{
$this->subQuery = $query;
$this->setSearchStatus(true);
}
public function isSearchDone(): bool
{
return $this->isSearchDone;
}
public function getSubQuery(): string
{
return $this->subQuery;
}
/**
* @param array $string
*/
public function setString($string): void
{
$this->string = $string;
}
public function getStrict(): bool
{
return $this->strict;
}
/**
* @param bool $val
*/
public function setStrict($val): void
{
$this->strict = $val;
}
public function getReturnParameters(): bool
{
return $this->returnParameters;
}
/**
* @param bool $val
*/
public function setReturnParameters($val): void
{
$this->returnParameters = $val;
}
/**
* @return array
*/
public function getParameters()
{
return $this->parameters;
}
/**
* @param array $val
*/
public function setParameters($val): void
{
$this->parameters = $val;
}
}

View File

@@ -0,0 +1,67 @@
<?php
namespace Mautic\LeadBundle\Event;
use Mautic\LeadBundle\Entity\Company;
use Mautic\LeadBundle\Entity\Lead;
use Symfony\Contracts\EventDispatcher\Event;
class LeadChangeCompanyEvent extends Event
{
private ?Lead $lead = null;
/**
* @var Lead[]|null
*/
private ?array $leads = null;
/**
* @param Lead|Lead[] $leads
*/
public function __construct(
Lead|array $leads,
private Company $company,
private bool $added = true,
) {
if (is_array($leads)) {
$this->leads = $leads;
} else {
$this->lead = $leads;
}
}
/**
* Returns the Lead entity.
*
* @return Lead
*/
public function getLead()
{
return $this->lead;
}
/**
* Returns batch array of leads.
*
* @return array
*/
public function getLeads()
{
return $this->leads;
}
public function getCompany(): Company
{
return $this->company;
}
public function wasAdded(): bool
{
return $this->added;
}
public function wasRemoved(): bool
{
return !$this->added;
}
}

View File

@@ -0,0 +1,49 @@
<?php
namespace Mautic\LeadBundle\Event;
use Mautic\LeadBundle\Entity\Lead;
use Symfony\Contracts\EventDispatcher\Event;
class LeadChangeEvent extends Event
{
public function __construct(
private Lead $oldLead,
private $oldTrackingId,
private Lead $newLead,
private $newTrackingId,
) {
}
/**
* @return Lead
*/
public function getOldLead()
{
return $this->oldLead;
}
/**
* @return mixed
*/
public function getOldTrackingId()
{
return $this->oldTrackingId;
}
/**
* @return Lead
*/
public function getNewLead()
{
return $this->newLead;
}
/**
* @return mixed
*/
public function getNewTrackingId()
{
return $this->newTrackingId;
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace Mautic\LeadBundle\Event;
use Mautic\CoreBundle\Event\CommonEvent;
use Mautic\LeadBundle\Entity\LeadDevice;
class LeadDeviceEvent extends CommonEvent
{
/**
* @param bool $isNew
*/
public function __construct(LeadDevice &$device, $isNew = false)
{
$this->entity = &$device;
$this->isNew = $isNew;
}
/**
* Returns the LeadDevice entity.
*
* @return LeadDevice
*/
public function getDevice()
{
return $this->entity;
}
/**
* Sets the LeadDevice entity.
*/
public function setDevice(LeadDevice $device): void
{
$this->entity = $device;
}
}

View File

@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Mautic\CoreBundle\Event\CommonEvent;
use Mautic\LeadBundle\Entity\Lead;
final class LeadEvent extends CommonEvent
{
protected bool $alreadyProcessedInBatch = false;
public function __construct(
Lead $lead,
bool $isNew = false,
) {
$this->entity = $lead;
$this->isNew = $isNew;
}
public function getLead(): Lead
{
return $this->entity;
}
public function setLead(Lead $lead): void
{
$this->entity = $lead;
}
public function isAlreadyProcessedInBatch(): bool
{
return $this->alreadyProcessedInBatch;
}
public function setAlreadyProcessedInBatch(bool $alreadyProcessedInBatch): void
{
$this->alreadyProcessedInBatch = $alreadyProcessedInBatch;
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace Mautic\LeadBundle\Event;
use Mautic\CoreBundle\Event\CommonEvent;
use Mautic\LeadBundle\Entity\LeadField;
class LeadFieldEvent extends CommonEvent
{
/**
* @param bool $isNew
*/
public function __construct(LeadField &$field, $isNew = false)
{
$this->entity = &$field;
$this->isNew = $isNew;
}
/**
* Returns the Field entity.
*
* @return LeadField
*/
public function getField()
{
return $this->entity;
}
/**
* Sets the LeadField entity.
*/
public function setField(LeadField $field): void
{
$this->entity = $field;
}
}

View File

@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Mautic\LeadBundle\Entity\Lead;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Contracts\EventDispatcher\Event;
final class LeadGetCurrentEvent extends Event
{
private ?Lead $contact = null;
public function __construct(private ?Request $request = null)
{
}
public function getRequest(): ?Request
{
return $this->request;
}
public function getContact(): ?Lead
{
return $this->contact;
}
public function setContact(?Lead $contact): void
{
$this->contact = $contact;
}
}

View File

@@ -0,0 +1,36 @@
<?php
namespace Mautic\LeadBundle\Event;
use Mautic\CoreBundle\Event\CommonEvent;
use Mautic\LeadBundle\Entity\LeadList;
class LeadListEvent extends CommonEvent
{
/**
* @param bool $isNew
*/
public function __construct(LeadList $list, $isNew = false)
{
$this->entity = $list;
$this->isNew = $isNew;
}
/**
* Returns the List entity.
*
* @return LeadList
*/
public function getList()
{
return $this->entity;
}
/**
* Sets the List entity.
*/
public function setList(LeadList $list): void
{
$this->entity = $list;
}
}

View File

@@ -0,0 +1,130 @@
<?php
namespace Mautic\LeadBundle\Event;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\EntityManagerInterface;
use Mautic\CoreBundle\Event\CommonEvent;
use Mautic\LeadBundle\Segment\Query\QueryBuilder;
/**
* Please refer to LeadListRepository.php, inside getListFilterExprCombined method, for examples.
*/
class LeadListFilteringEvent extends CommonEvent
{
protected bool $isFilteringDone;
protected string $subQuery;
private string $leadsTableAlias;
/**
* @param array $details
* @param int $leadId
* @param string $alias
* @param string $func
* @param QueryBuilder $queryBuilder
*/
public function __construct(
protected $details,
protected $leadId,
protected $alias,
protected $func,
protected $queryBuilder,
EntityManager $entityManager,
) {
$this->em = $entityManager;
$this->isFilteringDone = false;
$this->subQuery = '';
$this->leadsTableAlias = $queryBuilder->getTableAlias(MAUTIC_TABLE_PREFIX.'leads');
}
/**
* @return array
*/
public function getDetails()
{
return $this->details;
}
/**
* @return int
*/
public function getLeadId()
{
return $this->leadId;
}
/**
* @return string
*/
public function getAlias()
{
return $this->alias;
}
/**
* @return string
*/
public function getFunc()
{
return $this->func;
}
/**
* @return EntityManagerInterface
*/
public function getEntityManager()
{
return $this->em;
}
/**
* @return QueryBuilder
*/
public function getQueryBuilder()
{
return $this->queryBuilder;
}
/**
* @param bool $status
*/
public function setFilteringStatus($status): void
{
$this->isFilteringDone = $status;
}
/**
* @param string $query
*/
public function setSubQuery($query): void
{
$this->subQuery = $query;
$this->setFilteringStatus(true);
}
public function isFilteringDone(): bool
{
return $this->isFilteringDone;
}
public function getSubQuery(): string
{
return $this->subQuery;
}
/**
* @param array $details
*/
public function setDetails($details): void
{
$this->details = $details;
}
public function getLeadsTableAlias(): string
{
return $this->leadsTableAlias;
}
}

View File

@@ -0,0 +1,117 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Mautic\CoreBundle\Event\AbstractCustomRequestEvent;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Contracts\Translation\TranslatorInterface;
class LeadListFiltersChoicesEvent extends AbstractCustomRequestEvent
{
/**
* @param mixed[] $choices
* @param mixed[] $operators Please refer to ListModel.php, inside getChoiceFields method, for default operators availabled.
*/
public function __construct(
protected $choices,
protected $operators,
protected TranslatorInterface $translator,
?Request $request = null,
private string $search = '',
) {
parent::__construct($request);
}
/**
* @return mixed[]
*/
public function getChoices()
{
return $this->choices;
}
/**
* @return mixed[]
*/
public function getOperators()
{
return $this->operators;
}
/**
* @return TranslatorInterface
*/
public function getTranslator()
{
return $this->translator;
}
public function getSearch(): string
{
return $this->search;
}
/**
* Add a new choice for list filters
* Please refer to ListModel.php, inside getChoiceFields method, for examples of choices.
*
* @param string $object
* @param string $choiceKey
* @param mixed[] $choiceConfig
*/
public function addChoice($object, $choiceKey, $choiceConfig): void
{
if (!isset($this->choices[$object])) {
$this->choices[$object] = [];
}
if (!array_key_exists($choiceKey, $this->choices[$object])) {
$this->choices[$object][$choiceKey] = $choiceConfig;
}
}
/**
* @param mixed[] $choiceConfig
*/
public function setChoice(string $object, string $choiceKey, array $choiceConfig): void
{
if (!isset($this->choices[$object])) {
$this->choices[$object] = [];
}
$this->choices[$object][$choiceKey] = $choiceConfig;
}
/**
* @param array<string,array<string,string>> $choices
*/
public function setChoices(array $choices): void
{
$this->choices = $choices;
}
public function isForSegmentation(): bool
{
$route = (string) $this->getRoute();
// segment form
if ('mautic_segment_action' === $route) {
return true;
}
// segment API
if (str_starts_with($route, 'mautic_api_lists')) {
return true;
}
// ajax request to load the filter's value fields
$request = $this->getRequest();
if ('loadSegmentFilterForm' === $request->attributes->get('action')) {
return true;
}
// something else such as dynamic content
return false;
}
}

View File

@@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Mautic\CoreBundle\Event\CommonEvent;
use Mautic\LeadBundle\Segment\ContactSegmentFilterCrate;
use Mautic\LeadBundle\Segment\Decorator\FilterDecoratorInterface;
final class LeadListFiltersDecoratorDelegateEvent extends CommonEvent
{
private ?FilterDecoratorInterface $decorator = null;
public function __construct(
private ContactSegmentFilterCrate $crate,
) {
}
public function getDecorator(): ?FilterDecoratorInterface
{
return $this->decorator;
}
public function setDecorator(FilterDecoratorInterface $decorator): self
{
$this->decorator = $decorator;
return $this;
}
public function getCrate(): ContactSegmentFilterCrate
{
return $this->crate;
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace Mautic\LeadBundle\Event;
use Mautic\CoreBundle\Event\CommonEvent;
use Symfony\Contracts\Translation\TranslatorInterface;
class LeadListFiltersOperatorsEvent extends CommonEvent
{
/**
* @deprecated to be removed in Mautic 3
*
* @param array $operators @deprecated to be removed in Mautic 3. Subscribe operators instead.
* @param TranslatorInterface $translator @deprecated to be removed in Mautic 3
*/
public function __construct(
protected $operators,
protected TranslatorInterface $translator,
) {
}
/**
* @return array
*/
public function getOperators()
{
return $this->operators;
}
/**
* Add a new operator for list filters
* Please refer to OperatorListTrait.php, inside getFilterExpressionFunctions method, for examples of operators.
*
* @see OperatorListTrait
*
* @param string $operatorKey
* @param array $operatorConfig
*/
public function addOperator($operatorKey, $operatorConfig): void
{
if (!array_key_exists($operatorKey, $this->operators)) {
$this->operators[$operatorKey] = $operatorConfig;
}
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace Mautic\LeadBundle\Event;
use Mautic\CoreBundle\Event\CommonEvent;
class LeadListMergeFiltersEvent extends CommonEvent
{
/**
* @param mixed[] $filters
*/
public function __construct(private array $filters)
{
}
/**
* @return mixed[]
*/
public function getFilters(): array
{
return $this->filters;
}
/**
* @param mixed[] $filters
*/
public function setFilters(array $filters): void
{
$this->filters = $filters;
}
}

View File

@@ -0,0 +1,32 @@
<?php
namespace Mautic\LeadBundle\Event;
use Mautic\LeadBundle\Entity\LeadList;
use Mautic\LeadBundle\Segment\Query\QueryBuilder;
use Symfony\Contracts\EventDispatcher\Event;
class LeadListQueryBuilderGeneratedEvent extends Event
{
public function __construct(
private LeadList $segment,
private QueryBuilder $queryBuilder,
) {
}
/**
* @return LeadList
*/
public function getSegment()
{
return $this->segment;
}
/**
* @return QueryBuilder
*/
public function getQueryBuilder()
{
return $this->queryBuilder;
}
}

View File

@@ -0,0 +1,33 @@
<?php
namespace Mautic\LeadBundle\Event;
use Mautic\LeadBundle\Entity\Lead;
use Symfony\Contracts\EventDispatcher\Event;
class LeadMergeEvent extends Event
{
public function __construct(
private Lead $victor,
private Lead $loser,
) {
}
/**
* Returns the victor (loser merges into the victor).
*
* @return Lead
*/
public function getVictor()
{
return $this->victor;
}
/**
* Returns the loser (loser merges into the victor).
*/
public function getLoser()
{
return $this->loser;
}
}

View File

@@ -0,0 +1,47 @@
<?php
namespace Mautic\LeadBundle\Event;
use Mautic\CoreBundle\Event\CommonEvent;
use Mautic\LeadBundle\Entity\Lead;
use Mautic\LeadBundle\Entity\LeadNote;
class LeadNoteEvent extends CommonEvent
{
/**
* @param bool $isNew
*/
public function __construct(LeadNote $note, $isNew = false)
{
$this->entity = $note;
$this->isNew = $isNew;
}
/**
* Returns the LeadNote entity.
*
* @return LeadNote
*/
public function getNote()
{
return $this->entity;
}
/**
* Sets the LeadNote entity.
*/
public function setLeadNote(LeadNote $note): void
{
$this->entity = $note;
}
/**
* Returns the Lead.
*
* @return Lead
*/
public function getLead()
{
return $this->entity->getLead();
}
}

View File

@@ -0,0 +1,575 @@
<?php
namespace Mautic\LeadBundle\Event;
use Mautic\CoreBundle\Helper\Chart\ChartQuery;
use Mautic\CoreBundle\Helper\DateTimeHelper;
use Mautic\LeadBundle\Entity\Lead;
use Symfony\Contracts\EventDispatcher\Event;
class LeadTimelineEvent extends Event
{
/**
* Container with all filtered events.
*
* @var array
*/
protected $events = [];
/**
* Container with all registered events types.
*
* @var array
*/
protected $eventTypes = [];
/**
* Array of filters
* search => (string) search term
* includeEvents => (array) event types to include
* excludeEvents => (array) event types to exclude.
*
* @var array
*/
protected $filters = [];
/**
* @var array<string, int>
*/
protected $totalEvents = [];
/**
* @var array
*/
protected $totalEventsByUnit = [];
/**
* @var bool
*/
protected $countOnly = false;
/**
* @var \DateTimeInterface|null
*/
protected $dateFrom;
/**
* @var \DateTimeInterface|null
*/
protected $dateTo;
/**
* Time unit to group counts by (M = month, D = day, Y = year, null = no grouping).
*
* @var string
*/
protected $groupUnit;
/**
* @var ChartQuery
*/
protected $chartQuery;
/**
* @var bool
*/
protected $fetchTypesOnly = false;
/**
* @var array
*/
protected $serializerGroups = [
'ipAddressList',
];
/**
* @param Lead|null $lead Lead entity for the lead the timeline is being generated for
* @param int $page
* @param int $limit Limit per type
* @param bool $forTimeline
* @param string|null $siteDomain
*/
public function __construct(
protected ?Lead $lead = null,
array $filters = [],
protected ?array $orderBy = null,
protected $page = 1,
protected $limit = 25,
protected $forTimeline = true,
protected $siteDomain = null,
) {
$this->filters = !empty($filters)
? $filters
:
[
'search' => '',
'includeEvents' => [],
'excludeEvents' => [],
];
if (!empty($filters['dateFrom'])) {
$this->dateFrom = ($filters['dateFrom'] instanceof \DateTime) ? $filters['dateFrom'] : new \DateTime($filters['dateFrom']);
}
if (!empty($filters['dateTo'])) {
$this->dateTo = ($filters['dateTo'] instanceof \DateTime) ? $filters['dateTo'] : new \DateTime($filters['dateTo']);
}
}
/**
* Add an event to the container.
*
* The data should be an associative array with the following data:
* 'event' => string The event name
* 'timestamp' => \DateTime The timestamp of the event
* 'extra' => array An optional array of extra data for the event
*
* @param array $data Data array for the table
*/
public function addEvent(array $data): void
{
if ($this->countOnly) {
// BC support for old format
if ($this->groupUnit && $this->chartQuery) {
$countData = [
[
'date' => $data['timestamp'],
'count' => 1,
],
];
$count = $this->chartQuery->completeTimeData($countData);
$this->addToCounter($data['event'], $count);
} else {
if (!isset($this->totalEvents[$data['event']])) {
$this->totalEvents[$data['event']] = 0;
}
++$this->totalEvents[$data['event']];
}
} else {
if (!isset($this->events[$data['event']])) {
$this->events[$data['event']] = [];
}
if (!$this->isForTimeline()) {
// standardize the payload
$keepThese = [
'event' => true,
'eventId' => true,
'eventLabel' => true,
'eventType' => true,
'timestamp' => true,
'contactId' => true,
'extra' => true,
];
$data = array_intersect_key($data, $keepThese);
// Rename extra to details
if (isset($data['extra'])) {
$data['details'] = $data['extra'];
$data['details'] = $this->prepareDetailsForAPI($data['details']);
unset($data['extra']);
}
// Ensure a full URL
if ($this->siteDomain && isset($data['eventLabel']) && is_array($data['eventLabel']) && isset($data['eventLabel']['href'])) {
// If this does not have a http, then assume a Mautic URL
if (!str_contains($data['eventLabel']['href'], '://')) {
$data['eventLabel']['href'] = $this->siteDomain.$data['eventLabel']['href'];
}
}
}
if (empty($data['eventId'])) {
// Every entry should have an eventId so generate one if the listener itself didn't handle this
$data['eventId'] = $this->generateEventId($data);
}
$this->events[$data['event']][] = $data;
}
}
/**
* Fetch the events.
*
* @return array Events sorted by timestamp with most recent event first
*/
public function getEvents()
{
if (empty($this->events)) {
return [];
}
$events = call_user_func_array('array_merge', array_values($this->events));
foreach ($events as &$e) {
if (!$e['timestamp'] instanceof \DateTime) {
$dt = new DateTimeHelper($e['timestamp'], 'Y-m-d H:i:s', 'UTC');
$e['timestamp'] = $dt->getDateTime();
unset($dt);
}
}
if (!empty($this->orderBy)) {
usort(
$events,
function ($a, $b) {
switch ($this->orderBy[0]) {
case 'eventLabel':
$aLabel = '';
if (isset($a['eventLabel'])) {
$aLabel = (is_array($a['eventLabel'])) ? $a['eventLabel']['label'] : $a['eventLabel'];
}
$bLabel = '';
if (isset($b['eventLabel'])) {
$bLabel = (is_array($b['eventLabel'])) ? $b['eventLabel']['label'] : $b['eventLabel'];
}
return strnatcmp($aLabel, $bLabel);
case 'timestamp':
if ($a['timestamp'] == $b['timestamp']) {
$aPriority = isset($a['eventPriority']) ? (int) $a['eventPriority'] : 0;
$bPriority = isset($b['eventPriority']) ? (int) $b['eventPriority'] : 0;
return $aPriority - $bPriority;
}
return $a['timestamp'] < $b['timestamp'] ? -1 : 1;
}
}
);
if ('DESC' == $this->orderBy[1]) {
$events = array_reverse($events);
}
}
return $events;
}
/**
* Get the max number of pages for pagination.
*
* @return float|int
*/
public function getMaxPage()
{
if (!$this->totalEvents) {
return 1;
}
// Find the type that has the largest number of total records
$largest = max($this->totalEvents);
// Max page is $largest / $limit
return ($largest) ? ceil($largest / $this->limit) : 1;
}
/**
* Add an event type to the container.
*
* @param string $eventTypeKey Identifier of the event type
* @param string $eventTypeName Name of the event type for humans
*/
public function addEventType($eventTypeKey, $eventTypeName): void
{
$this->eventTypes[$eventTypeKey] = $eventTypeName;
}
/**
* Fetch the event types.
*
* @return array of available types
*/
public function getEventTypes()
{
natcasesort($this->eventTypes);
return $this->eventTypes;
}
/**
* Fetch the filter array for queries.
*
* @return array of wanted filteres. Empty == all
*/
public function getEventFilters()
{
return $this->filters['search'];
}
/**
* Fetch the order for queries.
*
* @return array|null
*/
public function getEventOrder()
{
return $this->orderBy;
}
/**
* Fetch start/limit for queries.
*/
public function getEventLimit(): array
{
return [
'leadId' => ($this->lead instanceof Lead) ? $this->lead->getId() : null,
'limit' => $this->limit,
'start' => (1 >= $this->page) ? 0 : ($this->page - 1) * $this->limit,
];
}
public function getQueryOptions(): array
{
return array_merge(
[
'search' => $this->filters['search'],
'order' => $this->orderBy,
'paginated' => !$this->countOnly,
'unitCounts' => $this->countOnly && $this->groupUnit,
'unit' => $this->groupUnit,
'fromDate' => $this->dateFrom,
'toDate' => $this->dateTo,
'chartQuery' => $this->chartQuery,
],
$this->getEventLimit()
);
}
/**
* Fetches the lead being acted on.
*
* @return Lead
*/
public function getLead()
{
return $this->lead;
}
/**
* Returns the lead ID if any.
*/
public function getLeadId(): ?int
{
return ($this->lead instanceof Lead) ? $this->lead->getId() : null;
}
/**
* Determine if an event type should be included.
*
* @param bool $inclusive
*/
public function isApplicable($eventType, $inclusive = false): bool
{
if ($this->fetchTypesOnly) {
return false;
}
if (in_array($eventType, $this->filters['excludeEvents'])) {
return false;
}
if (!empty($this->filters['includeEvents'])) {
if (!in_array($eventType, $this->filters['includeEvents'])) {
return false;
}
} elseif ($inclusive) {
return false;
}
return true;
}
/**
* Check if the event is getting an engagement count only.
*
* @return bool
*/
public function isEngagementCount()
{
return $this->countOnly;
}
/**
* Get the date range to get counts by.
*/
public function getCountDateRange(): array
{
return ['from' => $this->dateFrom, 'to' => $this->dateTo];
}
/**
* Get the unit counts are to be grouped by.
*
* @return string
*/
public function getCountGroupingUnit()
{
return $this->groupUnit;
}
/**
* Get total number of events for pagination.
*
* @return mixed[]
*/
public function getEventCounter(): array
{
// BC support for old formats
foreach ($this->events as $type => $events) {
if (!isset($this->totalEvents[$type])) {
$this->totalEvents[$type] = count($events);
}
}
$counter = [
'total' => array_sum($this->totalEvents),
];
if ($this->countOnly && $this->groupUnit) {
$counter['byUnit'] = $this->totalEventsByUnit;
}
return $counter;
}
/**
* Add to the event counters.
*
* @param int|array $count
*/
public function addToCounter($eventType, $count): void
{
if (!isset($this->totalEvents[$eventType])) {
$this->totalEvents[$eventType] = 0;
}
if (is_array($count)) {
if (isset($count['total'])) {
$this->totalEvents[$eventType] += $count['total'];
} elseif ($this->isEngagementCount() && $this->groupUnit) {
// Group counts across events by unit
foreach ($count as $key => $data) {
if (!isset($this->totalEventsByUnit[$key])) {
$this->totalEventsByUnit[$key] = 0;
}
$this->totalEventsByUnit[$key] += (int) $data;
$this->totalEvents[$eventType] += (int) $data;
}
} else {
$this->totalEvents[$eventType] = array_sum($count);
}
} else {
$this->totalEvents[$eventType] += (int) $count;
}
}
/**
* Subtract from the total counter if there is an event that was skipped for whatever reason.
*/
public function subtractFromCounter($eventType, $count = 1): void
{
$this->totalEvents[$eventType] -= $count;
}
/**
* Calculate engagement counts only.
*/
public function setCountOnly(\DateTime $dateFrom, \DateTime $dateTo, $groupUnit = null, ?ChartQuery $chartQuery = null): void
{
$this->countOnly = true;
$this->dateFrom = $dateFrom;
$this->dateTo = $dateTo;
$this->groupUnit = $groupUnit;
$this->chartQuery = $chartQuery;
}
/**
* Get chart query helper to format dates.
*
* @return ChartQuery
*/
public function getChartQuery()
{
return $this->chartQuery;
}
/**
* Check if the data is to be display for the contact's timeline or used for the API.
*
* @return bool
*/
public function isForTimeline()
{
return $this->forTimeline;
}
/**
* Add a serializer group for API formatting.
*/
public function addSerializerGroup($group): void
{
if (is_array($group)) {
$this->serializerGroups = array_merge(
$this->serializerGroups,
$group
);
} else {
$this->serializerGroups[$group] = $group;
}
}
/**
* @return array
*/
public function getSerializerGroups()
{
return $this->serializerGroups;
}
/**
* Will cause isApplicable to return false for all in order to just compile a list of event types.
*/
public function fetchTypesOnly(): void
{
$this->fetchTypesOnly = true;
}
/**
* Convert all snake case keys o camel case for API congruency.
*/
private function prepareDetailsForAPI(array $details): array
{
foreach ($details as $key => &$detailValues) {
if (is_array($detailValues)) {
$this->prepareDetailsForAPI($detailValues);
}
if ('lead_id' === $key) {
// Don't include this as it should be included in parent as contactId
unset($details[$key]);
continue;
}
if (strstr($key, '_')) {
$newKey = lcfirst(str_replace('_', '', ucwords($key, '_')));
$details[$newKey] = $details[$key];
unset($details[$key]);
}
}
return $details;
}
/**
* Generate something consistent for this event to identify this log entry.
*/
private function generateEventId(array $data): string
{
return $data['eventType'].hash('crc32', json_encode($data), false);
}
}

View File

@@ -0,0 +1,34 @@
<?php
namespace Mautic\LeadBundle\Event;
use Mautic\CoreBundle\Event\CommonEvent;
use Mautic\LeadBundle\Entity\Lead;
class LeadUtmTagsEvent extends CommonEvent
{
/**
* @param mixed[] $utmtags
*/
public function __construct(
Lead $lead,
protected array $utmtags,
) {
$this->entity = $lead;
}
public function getLead(): Lead
{
return $this->entity;
}
/**
* Returns the new points.
*
* @return mixed[]
*/
public function getUtmTags(): array
{
return $this->utmtags;
}
}

View File

@@ -0,0 +1,76 @@
<?php
namespace Mautic\LeadBundle\Event;
use Mautic\LeadBundle\Entity\Lead;
use Mautic\LeadBundle\Entity\LeadList;
use Symfony\Contracts\EventDispatcher\Event;
class ListChangeEvent extends Event
{
private Lead $lead;
/**
* @var Lead[]|null
*/
private ?array $leads = null;
/**
* @param Lead[]|Lead $leads
*/
public function __construct(
Lead|array $leads,
private LeadList $list,
private bool $added = true,
private ?\DateTime $date = null,
) {
if (is_array($leads)) {
$this->leads = $leads;
} else {
$this->lead = $leads;
}
}
/**
* Returns the Lead entity.
*
* @return Lead
*/
public function getLead()
{
return $this->lead;
}
/**
* @return LeadList
*/
public function getList()
{
return $this->list;
}
/**
* Returns batch array of leads.
*
* @return array|null
*/
public function getLeads()
{
return $this->leads;
}
public function wasAdded(): bool
{
return $this->added;
}
public function wasRemoved(): bool
{
return !$this->added;
}
public function getDate(): ?\DateTime
{
return $this->date;
}
}

View File

@@ -0,0 +1,67 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Symfony\Contracts\EventDispatcher\Event;
/**
* Event that collects choices for different list field types.
*/
final class ListFieldChoicesEvent extends Event
{
/**
* @var array<string,mixed[]>
*/
private array $choicesForTypes = [];
/**
* @var array<string,mixed[]>
*/
private array $choicesForAliases = [];
private string $searchTerm = '';
/**
* @param mixed[] $choices
*/
public function setChoicesForFieldType(string $fieldType, array $choices): void
{
$this->choicesForTypes[$fieldType] = $choices;
}
/**
* @param mixed[] $choices
*/
public function setChoicesForFieldAlias(string $fieldAlias, array $choices): void
{
$this->choicesForAliases[$fieldAlias] = $choices;
}
/**
* @return array<string,mixed[]>
*/
public function getChoicesForAllListFieldTypes(): array
{
return $this->choicesForTypes;
}
/**
* @return array<string,mixed[]>
*/
public function getChoicesForAllListFieldAliases(): array
{
return $this->choicesForAliases;
}
public function setSearchTerm(string $searchTerm): void
{
$this->searchTerm = $searchTerm;
}
public function getSearchTerm(): string
{
return $this->searchTerm;
}
}

View File

@@ -0,0 +1,56 @@
<?php
namespace Mautic\LeadBundle\Event;
use Mautic\CoreBundle\Event\CommonEvent;
class ListPreProcessListEvent extends CommonEvent
{
protected $result;
/**
* @param bool $isNew
*/
public function __construct(
protected array $list,
$isNew = false,
) {
$this->isNew = $isNew;
}
/**
* Returns the List entity.
*
* @return array
*/
public function getList()
{
return $this->list;
}
/**
* Sets the lead list entity.
*/
public function setList(array $list): void
{
$this->list = $list;
}
/**
* @return bool
*/
public function getResult()
{
return $this->result;
}
/**
* @return $this
*/
public function setResult($result)
{
$this->result = $result;
return $this;
}
}

View File

@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Symfony\Contracts\EventDispatcher\Event;
final class ListTypeaheadEvent extends Event
{
/**
* @var mixed[]
*/
private array $dataArray = [];
public function __construct(private string $fieldAlias, private string $filter)
{
}
public function getFieldAlias(): string
{
return $this->fieldAlias;
}
public function getFilter(): string
{
return $this->filter;
}
/**
* @return mixed[]
*/
public function getDataArray(): array
{
return $this->dataArray;
}
/**
* @param mixed[] $dataArray
*/
public function setDataArray(array $dataArray): void
{
$this->dataArray = $dataArray;
}
}

View File

@@ -0,0 +1,46 @@
<?php
namespace Mautic\LeadBundle\Event;
use Mautic\CoreBundle\Event\CommonEvent;
use Mautic\LeadBundle\Entity\Lead;
class PointsChangeEvent extends CommonEvent
{
protected int $old;
protected int $new;
public function __construct(Lead &$lead, $old, $new)
{
$this->entity = &$lead;
$this->old = (int) $old;
$this->new = (int) $new;
}
/**
* Returns the Lead entity.
*
* @return Lead
*/
public function getLead()
{
return $this->entity;
}
/**
* Returns the new points.
*/
public function getNewPoints(): int
{
return $this->new;
}
/**
* Returns the old points.
*/
public function getOldPoints(): int
{
return $this->old;
}
}

View File

@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Symfony\Contracts\EventDispatcher\Event;
final class SaveBatchLeadsEvent extends Event
{
public function __construct(
/**
* @var LeadEvent[]
*/
protected array $leadsEvents,
) {
}
/**
* @return LeadEvent[]
*/
public function getLeadsEvents(): array
{
return $this->leadsEvents;
}
}

View File

@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Mautic\CoreBundle\Event\CommonEvent;
/**
* SegmentDictionaryGenerationEvent is dispatched while dictionary to transform frontend filters into
* translation understandable by segment service is run.
*
* This is not related to language translations at all
*/
class SegmentDictionaryGenerationEvent extends CommonEvent
{
/**
* @param array<string,mixed[]> $translations
*/
public function __construct(
private array $translations = [],
) {
}
/**
* @param mixed[] $attributes
*
* @return SegmentDictionaryGenerationEvent
*/
public function addTranslation(string $key, $attributes)
{
$this->translations[$key] = $attributes;
return $this;
}
/**
* @return array<string,mixed[]>
*/
public function getTranslations()
{
return $this->translations;
}
public function hasTranslation(string $key): bool
{
return isset($this->translations[$key]);
}
}

View File

@@ -0,0 +1,81 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Doctrine\DBAL\Query\Expression\CompositeExpression;
use Mautic\LeadBundle\Segment\ContactSegmentFilter;
use Mautic\LeadBundle\Segment\Query\QueryBuilder;
use Symfony\Contracts\EventDispatcher\Event;
final class SegmentOperatorQueryBuilderEvent extends Event
{
private bool $operatorHandled = false;
private string $leadsTableAlias;
/**
* @param string|string[] $parameterHolder
*/
public function __construct(
private QueryBuilder $queryBuilder,
private ContactSegmentFilter $filter,
private $parameterHolder,
) {
$this->leadsTableAlias = $queryBuilder->getTableAlias(MAUTIC_TABLE_PREFIX.'leads');
}
public function getQueryBuilder(): QueryBuilder
{
return $this->queryBuilder;
}
public function getFilter(): ContactSegmentFilter
{
return $this->filter;
}
/**
* @return string|string[]
*/
public function getParameterHolder()
{
return $this->parameterHolder;
}
public function operatorIsOneOf(string ...$operators): bool
{
return in_array($this->filter->getOperator(), $operators, true);
}
/**
* @param CompositeExpression|string $expression
*/
public function addExpression($expression): void
{
$this->queryBuilder->addLogic($expression, $this->filter->getGlue());
$this->setOperatorHandled(true);
}
/**
* The subscriber must tell the event that the operator was successfully handled.
* Otherwise an exception will be thrown as an unknown operator was sent.
* Or use the addExpression() method that will set it automatically.
*/
public function setOperatorHandled(bool $wasHandled): void
{
$this->operatorHandled = $wasHandled;
}
public function wasOperatorHandled(): bool
{
return $this->operatorHandled;
}
public function getLeadsTableAlias(): string
{
return $this->leadsTableAlias;
}
}

View File

@@ -0,0 +1,28 @@
<?php
namespace Mautic\LeadBundle\Event;
use Mautic\CoreBundle\Event\CommonEvent;
use Mautic\LeadBundle\Entity\Tag;
class TagEvent extends CommonEvent
{
/**
* @param bool $isNew
*/
public function __construct(Tag $tag, $isNew = false)
{
$this->entity = $tag;
$this->isNew = $isNew;
}
/**
* Returns the Tag entity.
*
* @return Tag
*/
public function getTag()
{
return $this->entity;
}
}

View File

@@ -0,0 +1,40 @@
<?php
declare(strict_types=1);
namespace Mautic\LeadBundle\Event;
use Symfony\Contracts\EventDispatcher\Event;
/**
* Event that collects operators for different field types.
*/
final class TypeOperatorsEvent extends Event
{
/**
* @var array<string,mixed[]>
*/
private array $operators = [];
/**
* $operators example:
* [
* 'include' => ['=' => 'like'],
* 'exclude' => ['!=' => '!like'],
* ].
*
* @param array<string,mixed[]> $operators
*/
public function setOperatorsForFieldType(string $fieldType, array $operators): void
{
$this->operators[$fieldType] = $operators;
}
/**
* @return array<string,mixed[]>
*/
public function getOperatorsForAllFieldTypes(): array
{
return $this->operators;
}
}