Spaces:
No application file
No application file
namespace Mautic\FormBundle\Entity; | |
use Doctrine\DBAL\Types\Types; | |
use Doctrine\ORM\Mapping as ORM; | |
use Mautic\ApiBundle\Serializer\Driver\ApiMetadataDriver; | |
use Mautic\CoreBundle\Doctrine\Mapping\ClassMetadataBuilder; | |
use Mautic\CoreBundle\Helper\InputHelper; | |
use Mautic\FormBundle\ProgressiveProfiling\DisplayManager; | |
use Mautic\LeadBundle\Entity\Lead; | |
class Field | |
{ | |
/** | |
* @var int | |
*/ | |
private $id; | |
/** | |
* @var string | |
*/ | |
private $label; | |
/** | |
* @var bool|null | |
*/ | |
private $showLabel = true; | |
/** | |
* @var string | |
*/ | |
private $alias; | |
/** | |
* @var string | |
*/ | |
private $type; | |
/** | |
* @var bool | |
*/ | |
private $isCustom = false; | |
/** | |
* @var array | |
*/ | |
private $customParameters = []; | |
/** | |
* @var string|null | |
*/ | |
private $defaultValue; | |
/** | |
* @var bool | |
*/ | |
private $isRequired = false; | |
/** | |
* @var string|null | |
*/ | |
private $validationMessage; | |
/** | |
* @var string|null | |
*/ | |
private $helpMessage; | |
/** | |
* @var int|null | |
*/ | |
private $order = 0; | |
/** | |
* @var array | |
*/ | |
private $properties = []; | |
/** | |
* @var array | |
*/ | |
private $validation = []; | |
/** | |
* @var array<string,mixed>|null | |
*/ | |
private $conditions = []; | |
/** | |
* @var Form|null | |
*/ | |
private $form; | |
/** | |
* @var string|null | |
*/ | |
private $labelAttributes; | |
/** | |
* @var string|null | |
*/ | |
private $inputAttributes; | |
/** | |
* @var string|null | |
*/ | |
private $containerAttributes; | |
/** | |
* @var string|null | |
*/ | |
private $leadField; | |
/** | |
* @var bool|null | |
*/ | |
private $saveResult = true; | |
/** | |
* @var bool|null | |
*/ | |
private $isAutoFill = false; | |
/** | |
* @var array | |
*/ | |
private $changes; | |
private $sessionId; | |
/** | |
* @var bool|null | |
*/ | |
private $showWhenValueExists; | |
/** | |
* @var int|null | |
*/ | |
private $showAfterXSubmissions; | |
/** | |
* @var bool|null | |
*/ | |
private $alwaysDisplay; | |
/** | |
* @var string|null | |
*/ | |
private $parent; | |
/** | |
* @var string|null | |
*/ | |
private $mappedObject; | |
/** | |
* @var string|null | |
*/ | |
private $mappedField; | |
/** | |
* Reset properties on clone. | |
*/ | |
public function __clone() | |
{ | |
$this->id = null; | |
$this->form = null; | |
} | |
public static function loadMetadata(ORM\ClassMetadata $metadata): void | |
{ | |
$builder = new ClassMetadataBuilder($metadata); | |
$builder->setTable('form_fields') | |
->setCustomRepositoryClass(FieldRepository::class) | |
->addIndex(['type'], 'form_field_type_search'); | |
$builder->addId(); | |
$builder->addField('label', Types::TEXT); | |
$builder->addNullableField('showLabel', Types::BOOLEAN, 'show_label'); | |
$builder->addField('alias', Types::STRING); | |
$builder->addField('type', Types::STRING); | |
$builder->addNamedField('isCustom', Types::BOOLEAN, 'is_custom'); | |
$builder->addNullableField('customParameters', Types::ARRAY, 'custom_parameters'); | |
$builder->addNullableField('defaultValue', Types::TEXT, 'default_value'); | |
$builder->addNamedField('isRequired', Types::BOOLEAN, 'is_required'); | |
$builder->addNullableField('validationMessage', Types::TEXT, 'validation_message'); | |
$builder->addNullableField('helpMessage', Types::TEXT, 'help_message'); | |
$builder->addNullableField('order', Types::INTEGER, 'field_order'); | |
$builder->addNullableField('properties', Types::ARRAY); | |
$builder->addNullableField('validation', Types::JSON); | |
$builder->addNullableField('parent', 'string', 'parent_id'); | |
$builder->addNullableField('conditions', 'json'); | |
$builder->createManyToOne('form', 'Form') | |
->inversedBy('fields') | |
->addJoinColumn('form_id', 'id', false, false, 'CASCADE') | |
->build(); | |
$builder->addNullableField('labelAttributes', Types::STRING, 'label_attr'); | |
$builder->addNullableField('inputAttributes', Types::STRING, 'input_attr'); | |
$builder->addNullableField('containerAttributes', Types::STRING, 'container_attr'); | |
$builder->addNullableField('leadField', Types::STRING, 'lead_field'); | |
$builder->addNullableField('saveResult', Types::BOOLEAN, 'save_result'); | |
$builder->addNullableField('isAutoFill', Types::BOOLEAN, 'is_auto_fill'); | |
$builder->addNullableField('showWhenValueExists', Types::BOOLEAN, 'show_when_value_exists'); | |
$builder->addNullableField('showAfterXSubmissions', Types::INTEGER, 'show_after_x_submissions'); | |
$builder->addNullableField('alwaysDisplay', Types::BOOLEAN, 'always_display'); | |
$builder->addNullableField('mappedObject', Types::STRING, 'mapped_object'); | |
$builder->addNullableField('mappedField', Types::STRING, 'mapped_field'); | |
} | |
/** | |
* Prepares the metadata for API usage. | |
*/ | |
public static function loadApiMetadata(ApiMetadataDriver $metadata): void | |
{ | |
$metadata->setGroupPrefix('form') | |
->addProperties( | |
[ | |
'id', | |
'label', | |
'showLabel', | |
'alias', | |
'type', | |
'defaultValue', | |
'isRequired', | |
'validationMessage', | |
'helpMessage', | |
'order', | |
'properties', | |
'validation', | |
'parent', | |
'conditions', | |
'labelAttributes', | |
'inputAttributes', | |
'containerAttributes', | |
'leadField', // @deprecated, to be removed in Mautic 4. Use mappedObject and mappedField instead. | |
'saveResult', | |
'isAutoFill', | |
'mappedObject', | |
'mappedField', | |
] | |
) | |
->build(); | |
} | |
/** | |
* @param string $prop | |
* @param mixed $val | |
*/ | |
private function isChanged($prop, $val): void | |
{ | |
if ($this->$prop != $val) { | |
$this->changes[$prop] = [$this->$prop, $val]; | |
} | |
} | |
/** | |
* @return array | |
*/ | |
public function getChanges() | |
{ | |
return $this->changes; | |
} | |
/** | |
* Get id. | |
* | |
* @return int | |
*/ | |
public function getId() | |
{ | |
return $this->id; | |
} | |
/** | |
* Set label. | |
* | |
* @param string $label | |
* | |
* @return Field | |
*/ | |
public function setLabel($label) | |
{ | |
$this->isChanged('label', $label); | |
$this->label = $label; | |
return $this; | |
} | |
/** | |
* Get label. | |
* | |
* @return string | |
*/ | |
public function getLabel() | |
{ | |
return $this->label; | |
} | |
/** | |
* Set alias. | |
* | |
* @param string $alias | |
* | |
* @return Field | |
*/ | |
public function setAlias($alias) | |
{ | |
$this->isChanged('alias', $alias); | |
$this->alias = $alias; | |
return $this; | |
} | |
/** | |
* Get alias. | |
* | |
* @return string | |
*/ | |
public function getAlias() | |
{ | |
return $this->alias; | |
} | |
/** | |
* Set type. | |
* | |
* @param string $type | |
* | |
* @return Field | |
*/ | |
public function setType($type) | |
{ | |
$this->isChanged('type', $type); | |
$this->type = $type; | |
return $this; | |
} | |
/** | |
* Get type. | |
* | |
* @return string | |
*/ | |
public function getType() | |
{ | |
return $this->type; | |
} | |
/** | |
* Set defaultValue. | |
* | |
* @param string $defaultValue | |
* | |
* @return Field | |
*/ | |
public function setDefaultValue($defaultValue) | |
{ | |
$this->isChanged('defaultValue', $defaultValue); | |
$this->defaultValue = $defaultValue; | |
return $this; | |
} | |
/** | |
* Get defaultValue. | |
* | |
* @return string | |
*/ | |
public function getDefaultValue() | |
{ | |
return $this->defaultValue; | |
} | |
/** | |
* Set isRequired. | |
* | |
* @param bool $isRequired | |
* | |
* @return Field | |
*/ | |
public function setIsRequired($isRequired) | |
{ | |
$this->isChanged('isRequired', $isRequired); | |
$this->isRequired = $isRequired; | |
return $this; | |
} | |
/** | |
* Get isRequired. | |
* | |
* @return bool | |
*/ | |
public function getIsRequired() | |
{ | |
return $this->isRequired; | |
} | |
/** | |
* Proxy function to getIsRequired. | |
* | |
* @return bool | |
*/ | |
public function isRequired() | |
{ | |
return $this->getIsRequired(); | |
} | |
/** | |
* Set order. | |
* | |
* @param int $order | |
* | |
* @return Field | |
*/ | |
public function setOrder($order) | |
{ | |
$this->isChanged('order', $order); | |
$this->order = $order; | |
return $this; | |
} | |
/** | |
* Get order. | |
* | |
* @return int | |
*/ | |
public function getOrder() | |
{ | |
return $this->order; | |
} | |
/** | |
* Set properties. | |
* | |
* @param array $properties | |
* | |
* @return Field | |
*/ | |
public function setProperties($properties) | |
{ | |
$this->isChanged('properties', $properties); | |
$this->properties = $properties; | |
return $this; | |
} | |
/** | |
* Get properties. | |
* | |
* @return array | |
*/ | |
public function getProperties() | |
{ | |
return $this->properties; | |
} | |
/** | |
* Set validation. | |
* | |
* @param array $validation | |
* | |
* @return Field | |
*/ | |
public function setValidation($validation) | |
{ | |
$this->isChanged('validation', $validation); | |
$this->validation = $validation; | |
return $this; | |
} | |
/** | |
* Get validation. | |
* | |
* @return array | |
*/ | |
public function getValidation() | |
{ | |
return $this->validation; | |
} | |
/** | |
* Set validationMessage. | |
* | |
* @param string $validationMessage | |
* | |
* @return Field | |
*/ | |
public function setValidationMessage($validationMessage) | |
{ | |
$this->isChanged('validationMessage', $validationMessage); | |
$this->validationMessage = $validationMessage; | |
return $this; | |
} | |
/** | |
* Get validationMessage. | |
* | |
* @return string | |
*/ | |
public function getValidationMessage() | |
{ | |
return $this->validationMessage; | |
} | |
/** | |
* @return Field | |
*/ | |
public function setForm(Form $form) | |
{ | |
$this->form = $form; | |
return $this; | |
} | |
/** | |
* Get form. | |
* | |
* @return Form|null | |
*/ | |
public function getForm() | |
{ | |
return $this->form; | |
} | |
/** | |
* @param string $labelAttributes | |
* | |
* @return Field | |
*/ | |
public function setLabelAttributes($labelAttributes) | |
{ | |
$this->isChanged('labelAttributes', $labelAttributes); | |
$this->labelAttributes = $labelAttributes; | |
return $this; | |
} | |
/** | |
* @return string | |
*/ | |
public function getLabelAttributes() | |
{ | |
return $this->labelAttributes; | |
} | |
/** | |
* @param string $inputAttributes | |
* | |
* @return Field | |
*/ | |
public function setInputAttributes($inputAttributes) | |
{ | |
$this->isChanged('inputAttributes', $inputAttributes); | |
$this->inputAttributes = $inputAttributes; | |
return $this; | |
} | |
/** | |
* @return string | |
*/ | |
public function getInputAttributes() | |
{ | |
return $this->inputAttributes; | |
} | |
/** | |
* @return mixed | |
*/ | |
public function getContainerAttributes() | |
{ | |
return $this->containerAttributes; | |
} | |
/** | |
* @return $this | |
*/ | |
public function setContainerAttributes($containerAttributes) | |
{ | |
$this->containerAttributes = $containerAttributes; | |
return $this; | |
} | |
/** | |
* @return array<string,mixed> | |
*/ | |
public function convertToArray(): array | |
{ | |
return get_object_vars($this); | |
} | |
/** | |
* @param bool $showLabel | |
* | |
* @return Field | |
*/ | |
public function setShowLabel($showLabel) | |
{ | |
$this->isChanged('showLabel', $showLabel); | |
$this->showLabel = $showLabel; | |
return $this; | |
} | |
/** | |
* @return bool | |
*/ | |
public function getShowLabel() | |
{ | |
return $this->showLabel; | |
} | |
/** | |
* Proxy function to getShowLabel(). | |
* | |
* @return bool | |
*/ | |
public function showLabel() | |
{ | |
return $this->getShowLabel(); | |
} | |
/** | |
* @param string $helpMessage | |
* | |
* @return Field | |
*/ | |
public function setHelpMessage($helpMessage) | |
{ | |
$this->isChanged('helpMessage', $helpMessage); | |
$this->helpMessage = $helpMessage; | |
return $this; | |
} | |
/** | |
* @return string | |
*/ | |
public function getHelpMessage() | |
{ | |
return $this->helpMessage; | |
} | |
/** | |
* @param bool $isCustom | |
* | |
* @return Field | |
*/ | |
public function setIsCustom($isCustom) | |
{ | |
$this->isCustom = $isCustom; | |
return $this; | |
} | |
/** | |
* @return bool | |
*/ | |
public function getIsCustom() | |
{ | |
return $this->isCustom; | |
} | |
/** | |
* Proxy function to getIsCustom(). | |
* | |
* @return bool | |
*/ | |
public function isCustom() | |
{ | |
return $this->getIsCustom(); | |
} | |
/** | |
* @param array $customParameters | |
* | |
* @return Field | |
*/ | |
public function setCustomParameters($customParameters) | |
{ | |
$this->customParameters = $customParameters; | |
return $this; | |
} | |
/** | |
* @return array | |
*/ | |
public function getCustomParameters() | |
{ | |
return $this->customParameters; | |
} | |
/** | |
* @return mixed | |
*/ | |
public function getSessionId() | |
{ | |
return $this->sessionId; | |
} | |
/** | |
* @param mixed $sessionId | |
*/ | |
public function setSessionId($sessionId): void | |
{ | |
$this->sessionId = $sessionId; | |
} | |
/** | |
* @deprecated, to be removed in Mautic 4. Use mappedObject and mappedField instead. | |
* | |
* @return mixed | |
*/ | |
public function getLeadField() | |
{ | |
return $this->leadField; | |
} | |
/** | |
* @deprecated, to be removed in Mautic 4. Use mappedObject and mappedField instead. | |
* | |
* @param mixed $leadField | |
*/ | |
public function setLeadField($leadField): void | |
{ | |
$this->leadField = $leadField; | |
} | |
/** | |
* @return mixed | |
*/ | |
public function getSaveResult() | |
{ | |
return $this->saveResult; | |
} | |
/** | |
* @param mixed $saveResult | |
*/ | |
public function setSaveResult($saveResult): void | |
{ | |
$this->saveResult = $saveResult; | |
} | |
/** | |
* @return bool | |
*/ | |
public function getIsAutoFill() | |
{ | |
return $this->isAutoFill; | |
} | |
/** | |
* @param mixed $isAutoFill | |
*/ | |
public function setIsAutoFill($isAutoFill): void | |
{ | |
$this->isAutoFill = $isAutoFill; | |
} | |
/** | |
* @return bool | |
*/ | |
public function getShowWhenValueExists() | |
{ | |
return $this->showWhenValueExists; | |
} | |
/** | |
* @param bool $showWhenValueExists | |
*/ | |
public function setShowWhenValueExists($showWhenValueExists): void | |
{ | |
$this->showWhenValueExists = $showWhenValueExists; | |
} | |
/** | |
* @return int | |
*/ | |
public function getShowAfterXSubmissions() | |
{ | |
return $this->showAfterXSubmissions; | |
} | |
/** | |
* @param int $showAfterXSubmissions | |
*/ | |
public function setShowAfterXSubmissions($showAfterXSubmissions): void | |
{ | |
$this->showAfterXSubmissions = $showAfterXSubmissions; | |
} | |
/** | |
* Decide if the field should be displayed based on thr progressive profiling conditions. | |
* | |
* @param array|null $submissions | |
*/ | |
public function showForContact($submissions = null, Lead $lead = null, Form $form = null, DisplayManager $displayManager = null): bool | |
{ | |
// Always show in the kiosk mode | |
if (null !== $form && true === $form->getInKioskMode()) { | |
return true; | |
} | |
// Hide the field if there is the submission count limit and hide it until the limit is overcame | |
if (!$this->alwaysDisplay && $this->showAfterXSubmissions > 0 && null !== $submissions && $this->showAfterXSubmissions > count($submissions)) { | |
return false; | |
} | |
if (!$this->alwaysDisplay && false === $this->showWhenValueExists) { | |
// Hide the field if there is the value condition and if we already know the value for this field | |
if ($submissions) { | |
foreach ($submissions as $submission) { | |
if (!empty($submission[$this->alias]) && !$this->isAutoFill) { | |
return false; | |
} | |
} | |
} | |
// Hide the field if the value is already known from the lead profile | |
if (null !== $lead | |
&& $this->mappedField | |
&& 'contact' === $this->mappedObject | |
&& !empty($lead->getFieldValue($this->mappedField)) | |
&& !$this->isAutoFill | |
) { | |
return false; | |
} | |
} | |
if ($displayManager && $displayManager->useProgressiveProfilingLimit()) { | |
if (!$displayManager->showForField($this)) { | |
return false; | |
} | |
} | |
return true; | |
} | |
/** | |
* Was field displayed. | |
* | |
* @param mixed[] $data | |
*/ | |
public function showForConditionalField(array $data): bool | |
{ | |
if (!$parentField = $this->findParentFieldInForm()) { | |
return true; | |
} | |
if (!isset($data[$parentField->getAlias()])) { | |
return false; | |
} | |
$sendValues = $data[$parentField->getAlias()]; | |
if (!is_array($sendValues)) { | |
$sendValues = [$sendValues]; | |
} | |
foreach ($sendValues as $value) { | |
// any value | |
if ('' !== $value && !empty($this->conditions['any'])) { | |
return true; | |
} | |
if ('notIn' === $this->conditions['expr']) { | |
// value not matched | |
if ('' !== $value && !in_array(InputHelper::clean($value), $this->conditions['values'])) { | |
return true; | |
} | |
} elseif (in_array(InputHelper::clean($value), $this->conditions['values'])) { | |
return true; | |
} | |
} | |
return false; | |
} | |
public function isCaptchaType(): bool | |
{ | |
return 'captcha' === $this->type; | |
} | |
public function isFileType(): bool | |
{ | |
return 'file' === $this->type; | |
} | |
public function hasChoices(): bool | |
{ | |
$properties = $this->getProperties(); | |
return 'checkboxgrp' === $this->getType() | |
|| (key_exists('multiple', $properties) && 1 === $properties['multiple']); | |
} | |
/** | |
* @return bool | |
*/ | |
public function isAlwaysDisplay() | |
{ | |
return $this->alwaysDisplay; | |
} | |
/** | |
* @param bool $alwaysDisplay | |
*/ | |
public function setAlwaysDisplay($alwaysDisplay): void | |
{ | |
$this->alwaysDisplay = $alwaysDisplay; | |
} | |
/** | |
* @return array<string, mixed> | |
*/ | |
public function getConditions() | |
{ | |
return $this->conditions; | |
} | |
/** | |
* @param array<string, mixed> $conditions | |
* | |
* @return Field | |
*/ | |
public function setConditions($conditions) | |
{ | |
$this->isChanged('conditions', $conditions); | |
$this->conditions = $conditions; | |
return $this; | |
} | |
/** | |
* @param string $parent | |
* | |
* @return Field | |
*/ | |
public function setParent($parent) | |
{ | |
$this->isChanged('parent', $parent); | |
$this->parent = $parent; | |
return $this; | |
} | |
/** | |
* @return string | |
*/ | |
public function getParent() | |
{ | |
return $this->parent; | |
} | |
private function findParentFieldInForm(): ?Field | |
{ | |
if (!$this->parent) { | |
return null; | |
} | |
$fields = $this->getForm()->getFields(); | |
foreach ($fields as $field) { | |
if (intval($field->getId()) === intval($this->parent)) { | |
return $field; | |
} | |
} | |
return null; | |
} | |
public function getMappedObject(): ?string | |
{ | |
return $this->mappedObject; | |
} | |
public function setMappedObject(?string $mappedObject): void | |
{ | |
$this->mappedObject = $mappedObject; | |
$this->resetLeadFieldIfValueIsEmpty($mappedObject); | |
} | |
public function getMappedField(): ?string | |
{ | |
return $this->mappedField; | |
} | |
public function setMappedField(?string $mappedField): void | |
{ | |
$this->mappedField = $mappedField; | |
$this->resetLeadFieldIfValueIsEmpty($mappedField); | |
} | |
private function resetLeadFieldIfValueIsEmpty(?string $value): void | |
{ | |
if ($value) { | |
return; | |
} | |
$this->leadField = null; | |
} | |
} | |