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,19 @@
<?php
declare(strict_types=1);
namespace Mautic\PluginBundle\Form\Constraint;
use Symfony\Component\Validator\Constraint;
class CanPublish extends Constraint
{
public string $message = 'mautic.lead_list.not_allowed_plugin_publish';
public string $integrationName;
public function getDefaultOption(): string
{
return 'integrationName';
}
}

View File

@@ -0,0 +1,35 @@
<?php
declare(strict_types=1);
namespace Mautic\PluginBundle\Form\Constraint;
use Mautic\PluginBundle\Event\PluginIsPublishedEvent;
use Mautic\PluginBundle\PluginEvents;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
class CanPublishValidator extends ConstraintValidator
{
public function __construct(private EventDispatcherInterface $eventDispatcher)
{
}
public function validate(mixed $value, Constraint $constraint): void
{
if (1 !== $value) {
return;
}
if (!$constraint instanceof CanPublish) {
throw new \Symfony\Component\Validator\Exception\UnexpectedTypeException($constraint, CanPublish::class);
}
$event = new PluginIsPublishedEvent($value, $constraint->integrationName);
$event = $this->eventDispatcher->dispatch($event, PluginEvents::PLUGIN_IS_PUBLISHED_STATE_CHANGING);
if (!$event->isCanPublish()) {
$this->context->buildViolation($event->getMessage())
->addViolation();
}
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Mautic\PluginBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* @extends AbstractType<array<mixed>>
*/
class CompanyFieldsType extends AbstractType
{
use FieldsTypeTrait;
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$this->buildFormFields($builder, $options, $options['integration_fields'], $options['mautic_fields'], 'company', $options['limit'], $options['start']);
}
public function configureOptions(OptionsResolver $resolver): void
{
$this->configureFieldOptions($resolver, 'company');
}
public function getBlockPrefix(): string
{
return 'integration_company_fields';
}
public function buildView(FormView $view, FormInterface $form, array $options): void
{
$this->buildFieldView($view, $options);
}
}

View File

@@ -0,0 +1,177 @@
<?php
namespace Mautic\PluginBundle\Form\Type;
use Mautic\CoreBundle\Form\Type\FormButtonsType;
use Mautic\CoreBundle\Form\Type\StandAloneButtonType;
use Mautic\CoreBundle\Form\Type\YesNoButtonGroupType;
use Mautic\PluginBundle\Entity\Integration;
use Mautic\PluginBundle\Form\Constraint\CanPublish;
use Mautic\PluginBundle\Integration\AbstractIntegration;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* @extends AbstractType<Integration>
*/
class DetailsType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add('isPublished', YesNoButtonGroupType::class, [
'constraints' => [
new CanPublish($options['integration'] ?? ''),
],
]);
/** @var AbstractIntegration $integrationObject */
$integrationObject = $options['integration_object'];
/** @var Integration $integration */
$integration = $options['data'];
$formSettings = $integrationObject->getFormDisplaySettings();
$decryptedKeys = $integrationObject->decryptApiKeys($integration->getApiKeys());
$keys = $integrationObject->getRequiredKeyFields();
if (!empty($formSettings['hide_keys'])) {
foreach ($formSettings['hide_keys'] as $key) {
unset($keys[$key]);
}
}
$builder->add(
'apiKeys',
KeysType::class,
[
'label' => false,
'integration_keys' => $keys,
'data' => $decryptedKeys,
'integration_object' => $integrationObject,
]
);
$builder->addEventListener(
FormEvents::PRE_SUBMIT,
function (FormEvent $event) use ($keys, $decryptedKeys, $options): void {
$data = $event->getData();
$form = $event->getForm();
$form->add(
'apiKeys',
KeysType::class,
[
'label' => false,
'integration_keys' => $keys,
'data' => $decryptedKeys,
'integration_object' => $options['integration_object'],
'is_published' => (int) $data['isPublished'],
]
);
}
);
if (!empty($formSettings['requires_authorization'])) {
$label = ($integrationObject->isAuthorized()) ? 'reauthorize' : 'authorize';
$builder->add(
'authButton',
StandAloneButtonType::class,
[
'attr' => [
'class' => 'btn btn-success btn-lg',
'onclick' => 'Mautic.initiateIntegrationAuthorization()',
'icon' => 'ri-key-2-line',
],
'label' => 'mautic.integration.form.'.$label,
'disabled' => false,
]
);
}
$features = $integrationObject->getSupportedFeatures();
$tooltips = $integrationObject->getSupportedFeatureTooltips();
if (!empty($features)) {
// Check to see if the integration is a new entry and thus not configured
$configured = null !== $integration->getId();
$enabledFeatures = $integration->getSupportedFeatures();
$data = ($configured) ? $enabledFeatures : $features;
$choices = [];
foreach ($features as $f) {
$choices['mautic.integration.form.feature.'.$f] = $f;
}
$builder->add(
'supportedFeatures',
ChoiceType::class,
[
'choices' => $choices,
'expanded' => true,
'label_attr' => ['class' => 'control-label'],
'multiple' => true,
'label' => 'mautic.integration.form.features',
'required' => false,
'data' => $data,
'choice_attr' => function ($val) use ($tooltips): array {
if (array_key_exists($val, $tooltips)) {
return [
'data-toggle' => 'tooltip',
'title' => $tooltips[$val],
];
}
return [];
},
]
);
}
$builder->add(
'featureSettings',
FeatureSettingsType::class,
[
'label' => 'mautic.integration.form.feature.settings',
'required' => true,
'data' => $integration->getFeatureSettings(),
'label_attr' => ['class' => 'control-label'],
'integration' => $options['integration'],
'integration_object' => $integrationObject,
'lead_fields' => $options['lead_fields'],
'company_fields' => $options['company_fields'],
]
);
$builder->add('name', HiddenType::class, ['data' => $options['integration']]);
$builder->add('in_auth', HiddenType::class, ['mapped' => false]);
$builder->add('buttons', FormButtonsType::class);
if (!empty($options['action'])) {
$builder->setAction($options['action']);
}
$integrationObject->modifyForm($builder, $options);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults(
[
'data_class' => Integration::class,
]
);
$resolver->setRequired(['integration', 'integration_object', 'lead_fields', 'company_fields']);
$resolver->setAllowedTypes('integration_object', [AbstractIntegration::class]);
}
public function getBlockPrefix(): string
{
return 'integration_details';
}
}

View File

@@ -0,0 +1,156 @@
<?php
namespace Mautic\PluginBundle\Form\Type;
use Mautic\CoreBundle\Helper\CoreParametersHelper;
use Psr\Log\LoggerInterface;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* @extends AbstractType<array<mixed>>
*/
class FeatureSettingsType extends AbstractType
{
public function __construct(
protected RequestStack $requestStack,
protected CoreParametersHelper $coreParametersHelper,
protected LoggerInterface $logger,
) {
}
/**
* @param FormBuilderInterface<array<mixed>|null> $builder
* @param array<string, mixed> $options
*/
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$integrationObject = $options['integration_object'];
// add custom feature settings
$integrationObject->appendToForm($builder, $options['data'], 'features');
$leadFields = $options['lead_fields'];
$companyFields = $options['company_fields'];
$formModifier = function (FormInterface $form, $data, $method = 'get') use ($integrationObject, $leadFields, $companyFields): void {
$integrationName = $integrationObject->getName();
$session = $this->requestStack->getSession();
$limit = $session->get(
'mautic.plugin.'.$integrationName.'.lead.limit',
$this->coreParametersHelper->get('default_pagelimit')
);
$page = $session->get('mautic.plugin.'.$integrationName.'.lead.page', 1);
$companyPage = $session->get('mautic.plugin.'.$integrationName.'.company.page', 1);
$settings = [
'silence_exceptions' => false,
'feature_settings' => $data,
'ignore_field_cache' => (1 == $page && 'POST' !== strtoupper($method)) ? true : false,
];
try {
if (empty($fields)) {
$fields = $integrationObject->getFormLeadFields($settings);
$fields = $fields[0] ?? $fields;
}
if (isset($settings['feature_settings']['objects']) and in_array('company', $settings['feature_settings']['objects'])) {
if (empty($integrationCompanyFields)) {
$integrationCompanyFields = $integrationObject->getFormCompanyFields($settings);
}
if (isset($integrationCompanyFields['company'])) {
$integrationCompanyFields = $integrationCompanyFields['company'];
}
}
if (!is_array($fields)) {
$fields = [];
}
$error = '';
} catch (\Exception $e) {
$error = $e->getMessage();
$this->logger->error($e);
// Prevent pagination from confusing things by using the cache
$page = 1;
$fields = $integrationCompanyFields = [];
}
$enableDataPriority = $integrationObject->getDataPriority();
$form->add(
'leadFields',
FieldsType::class,
[
'label' => 'mautic.integration.leadfield_matches',
'required' => true,
'mautic_fields' => $leadFields,
'data' => $data,
'integration_fields' => $fields,
'enable_data_priority' => $enableDataPriority,
'integration' => $integrationObject->getName(),
'integration_object' => $integrationObject,
'limit' => $limit,
'page' => $page,
'mapped' => false,
'error_bubbling' => false,
]
);
if (!empty($integrationCompanyFields)) {
$form->add(
'companyFields',
CompanyFieldsType::class,
[
'label' => 'mautic.integration.companyfield_matches',
'required' => true,
'mautic_fields' => $companyFields,
'data' => $data,
'integration_fields' => $integrationCompanyFields,
'enable_data_priority' => $enableDataPriority,
'integration' => $integrationObject->getName(),
'integration_object' => $integrationObject,
'limit' => $limit,
'page' => $companyPage,
'mapped' => false,
'error_bubbling' => false,
]
);
}
if ('get' == $method && $error) {
$form->addError(new FormError($error));
}
};
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($formModifier): void {
$data = $event->getData();
$formModifier($event->getForm(), $data);
}
);
$builder->addEventListener(
FormEvents::PRE_SUBMIT,
function (FormEvent $event) use ($formModifier): void {
$data = $event->getData();
$formModifier($event->getForm(), $data, 'post');
}
);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setRequired(['integration', 'integration_object', 'lead_fields', 'company_fields']);
}
public function getBlockPrefix(): string
{
return 'integration_featuresettings';
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace Mautic\PluginBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* @extends AbstractType<array<mixed>>
*/
class FieldsType extends AbstractType
{
use FieldsTypeTrait;
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$this->buildFormFields($builder, $options, $options['integration_fields'], $options['mautic_fields'], '', $options['limit'], $options['start']);
}
public function configureOptions(OptionsResolver $resolver): void
{
$this->configureFieldOptions($resolver, 'lead');
}
public function getBlockPrefix(): string
{
return 'integration_fields';
}
public function buildView(FormView $view, FormInterface $form, array $options): void
{
$this->buildFieldView($view, $options);
}
}

View File

@@ -0,0 +1,268 @@
<?php
namespace Mautic\PluginBundle\Form\Type;
use Mautic\CoreBundle\Form\Type\ButtonGroupType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\Extension\Core\Type\HiddenType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\Options;
use Symfony\Component\OptionsResolver\OptionsResolver;
trait FieldsTypeTrait
{
/**
* @param string $fieldObject
*/
protected function buildFormFields(
FormBuilderInterface $builder,
array $options,
array $integrationFields,
array $mauticFields,
$fieldObject,
$limit,
$start,
) {
$builder->addEventListener(
FormEvents::PRE_SET_DATA,
function (FormEvent $event) use ($options, $integrationFields, $mauticFields, $fieldObject, $limit, $start): void {
$form = $event->getForm();
$index = 0;
$choices = [];
$requiredFields = [];
$optionalFields = [];
$group = [];
$fieldData = $event->getData();
foreach ($mauticFields as $key => $value) {
if (is_array($value)) {
$mauticFields[$key] = array_flip($value);
}
}
// First loop to build options
foreach ($integrationFields as $field => $details) {
$groupName = '0default';
if (is_array($details)) {
if (isset($details['group'])) {
if (!isset($choices[$details['group']])) {
$choices[$details['group']] = [];
}
$label = $details['optionLabel'] ?? $details['label'];
$group[$field] = $groupName = $details['group'];
$choices[$field] = $label;
} else {
$choices[$field] = $details['label'];
}
} else {
$choices[$field] = $details;
}
if (!isset($requiredFields[$groupName])) {
$requiredFields[$groupName] = [];
$optionalFields[$groupName] = [];
}
if (is_array($details) && (!empty($details['required']) || 'Email' == $choices[$field])) {
$requiredFields[$groupName][$field] = $details;
} else {
$optionalFields[$groupName][$field] = $details;
}
}
// Order the fields by label
ksort($requiredFields, SORT_NATURAL);
ksort($optionalFields, SORT_NATURAL);
$sortFieldsFunction = function ($a, $b): int {
if (is_array($a)) {
$aLabel = $a['optionLabel'] ?? $a['label'];
} else {
$aLabel = $a;
}
if (is_array($b)) {
$bLabel = $b['optionLabel'] ?? $b['label'];
} else {
$bLabel = $b;
}
return strnatcasecmp($aLabel, $bLabel);
};
$fields = [];
foreach ($requiredFields as $groupedFields) {
uasort($groupedFields, $sortFieldsFunction);
$fields = array_merge($fields, $groupedFields);
}
foreach ($optionalFields as $groupedFields) {
uasort($groupedFields, $sortFieldsFunction);
$fields = array_merge($fields, $groupedFields);
}
// Ensure that fields aren't hidden
if ($start > count($fields) || 0 == $options['page']) {
$start = 0;
}
$paginatedFields = array_slice($fields, $start, $limit);
$fieldsName = 'leadFields';
if ($fieldObject) {
$fieldsName = $fieldObject.'Fields';
}
if (isset($fieldData[$fieldsName])) {
$fieldData[$fieldsName] = $options['integration_object']->formatMatchedFields($fieldData[$fieldsName]);
}
foreach ($paginatedFields as $field => $details) {
$matched = isset($fieldData[$fieldsName][$field]);
$required = (int) (!empty($integrationFields[$field]['required']) || 'Email' == $choices[$field]);
++$index;
$form->add(
'label_'.$index,
TextType::class,
[
'label' => false,
'data' => $choices[$field],
'attr' => [
'class' => 'form-control integration-fields',
'data-required' => $required,
'data-label' => $choices[$field],
'placeholder' => $group[$field] ?? '',
'readonly' => true,
],
'by_reference' => true,
'mapped' => false,
]
);
if (isset($options['enable_data_priority']) and $options['enable_data_priority']) {
$updateName = 'update_mautic';
if ($fieldObject) {
$updateName .= '_'.$fieldObject;
}
$forceDirection = false;
$disabled = (isset($fieldData[$fieldsName][$field])) ? $options['integration_object']->isCompoundMauticField($fieldData[$fieldsName][$field]) : false;
$data = isset($fieldData[$updateName][$field]) ? (int) $fieldData[$updateName][$field] : 1;
// Force to use just one way for certainly fields
if (isset($fields[$field]['update_mautic'])) {
$data = (bool) $fields[$field]['update_mautic'];
$disabled = true;
$forceDirection = true;
}
$form->add(
$updateName.$index,
ButtonGroupType::class,
[
'choices' => [
'<btn class="btn-nospin ri-arrow-left-circle-line"></btn>' => 0,
'<btn class="btn-nospin ri-arrow-right-circle-line"></btn>' => 1,
],
'label' => false,
'data' => $data,
'placeholder' => false,
'attr' => [
'data-toggle' => 'tooltip',
'title' => 'mautic.plugin.direction.data.update',
'disabled' => $disabled,
'forceDirection'=> $forceDirection,
],
]
);
}
if (!$fieldObject) {
$mauticFields['mautic.lead.report.contact_id'] = 'mauticContactId';
$mauticFields['mautic.plugin.integration.contact.timeline.link'] = 'mauticContactTimelineLink';
$mauticFields['mautic.plugin.integration.contact.donotcontact.email'] = 'mauticContactIsContactableByEmail';
}
$form->add(
'm_'.$index,
ChoiceType::class,
[
'choices' => $mauticFields,
'label' => false,
'data' => $matched && isset($fieldData[$fieldsName][$field]) ? $fieldData[$fieldsName][$field] : '',
'label_attr' => ['class' => 'control-label'],
'attr' => [
'class' => 'field-selector',
'data-placeholder' => ' ',
'data-required' => $required,
'data-value' => $matched && isset($fieldData[$fieldsName][$field]) ? $fieldData[$fieldsName][$field] : '',
'data-choices' => $mauticFields,
],
]
);
$form->add(
'i_'.$index,
HiddenType::class,
[
'data' => $field,
'attr' => [
'data-required' => $required,
'data-value' => $field,
],
]
);
$form->add(
$field,
HiddenType::class,
[
'data' => $index,
'attr' => [
'data-required' => $required,
'data-value' => $index,
],
]
);
}
}
);
}
protected function configureFieldOptions(OptionsResolver $resolver, $object)
{
$resolver->setRequired(['integration_fields', 'mautic_fields', 'integration', 'integration_object', 'page']);
$resolver->setDefined([('lead' === $object) ? 'update_mautic' : 'update_mautic_company']);
$resolver->setDefaults(
[
'special_instructions' => function (Options $options) {
[$specialInstructions, $alertType] = $options['integration_object']->getFormNotes('leadfield_match');
return $specialInstructions;
},
'alert_type' => function (Options $options) {
[$specialInstructions, $alertType] = $options['integration_object']->getFormNotes('leadfield_match');
return $alertType;
},
'allow_extra_fields' => true,
'enable_data_priority' => false,
'totalFields' => fn (Options $options): int => count($options['integration_fields']),
'fixedPageNum' => fn (Options $options): float => ceil($options['totalFields'] / $options['limit']),
'limit' => 10,
'start' => fn (Options $options): int => (1 === (int) $options['page']) ? 0 : ((int) $options['page'] - 1) * (int) $options['limit'],
]
);
}
protected function buildFieldView(FormView $view, array $options)
{
$view->vars['specialInstructions'] = $options['special_instructions'];
$view->vars['alertType'] = $options['alert_type'];
$view->vars['integration'] = $options['integration'];
$view->vars['totalFields'] = $options['totalFields'];
$view->vars['page'] = $options['page'];
$view->vars['fixedPageNum'] = $options['fixedPageNum'];
}
}

View File

@@ -0,0 +1,40 @@
<?php
namespace Mautic\PluginBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* @extends AbstractType<array<mixed>>
*/
class IntegrationCampaignsType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$builder->add(
'campaign_member_status',
ChoiceType::class,
[
'choices' => array_flip($options['campaignContactStatus']),
'attr' => [
'class' => 'form-control', ],
'label' => 'mautic.plugin.integration.campaigns.member.status',
'required' => false,
]
);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults(
['campaignContactStatus' => []]);
}
public function getBlockPrefix(): string
{
return 'integration_campaign_status';
}
}

View File

@@ -0,0 +1,45 @@
<?php
namespace Mautic\PluginBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* @extends AbstractType<array<mixed>|mixed>
*/
class IntegrationConfigType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
if (null != $options['integration']) {
$options['integration']->appendToForm($builder, $options['data'], 'integration');
}
if (!empty($options['campaigns'])) {
$builder->add(
'campaigns',
ChoiceType::class,
[
'choices' => array_flip($options['campaigns']),
'attr' => [
'class' => 'form-control', 'onchange' => 'Mautic.getIntegrationCampaignStatus(this);', ],
'label' => 'mautic.plugin.integration.campaigns',
'placeholder' => 'mautic.plugin.config.campaign.member.chooseone',
'required' => false,
]
);
}
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setRequired(['integration']);
$resolver->setDefaults([
'label' => false,
'campaigns' => [],
]);
}
}

View File

@@ -0,0 +1,139 @@
<?php
namespace Mautic\PluginBundle\Form\Type;
use Mautic\PluginBundle\Helper\IntegrationHelper;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\NotBlank;
/**
* @extends AbstractType<mixed>
*/
class IntegrationsListType extends AbstractType
{
public function __construct(
private IntegrationHelper $integrationHelper,
) {
}
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$integrationObjects = $this->integrationHelper->getIntegrationObjects(null, $options['supported_features'], true);
$integrations = ['' => ''];
foreach ($integrationObjects as $object) {
$settings = $object->getIntegrationSettings();
if ($settings->isPublished()) {
$pluginName = $settings->getPlugin()->getName();
if (!isset($integrations[$pluginName])) {
$integrations[$pluginName] = [];
}
$integrations[$pluginName][$object->getDisplayName()] = $object->getName();
}
}
$builder->add(
'integration',
ChoiceType::class,
[
'choices' => $integrations,
'expanded' => false,
'label_attr' => ['class' => 'control-label'],
'multiple' => false,
'label' => 'mautic.integration.integration',
'attr' => [
'class' => 'form-control',
'tooltip' => 'mautic.integration.integration.tooltip',
'onchange' => 'Mautic.getIntegrationConfig(this);',
],
'required' => true,
'constraints' => [
new NotBlank(
['message' => 'mautic.core.value.required']
),
],
]
);
$formModifier = function (FormEvent $event) use ($integrationObjects): void {
$data = $event->getData();
$form = $event->getForm();
$statusChoices = [];
$campaignChoices = [];
if (!empty($data['integration'])) {
$integrationObject = $this->integrationHelper->getIntegrationObject($data['integration']);
if (method_exists($integrationObject, 'getCampaigns')) {
$campaigns = $integrationObject->getCampaigns();
if (isset($campaigns['records']) && !empty($campaigns['records'])) {
foreach ($campaigns['records'] as $campaign) {
$campaignChoices[$campaign['Id']] = $campaign['Name'];
}
}
}
if (method_exists($integrationObject, 'getCampaignMemberStatus') && isset($data['config']['campaigns'])) {
$campaignStatus = $integrationObject->getCampaignMemberStatus($data['config']['campaigns']);
if (isset($campaignStatus['records']) && !empty($campaignStatus['records'])) {
foreach ($campaignStatus['records'] as $campaignS) {
$statusChoices[$campaignS['Label']] = $campaignS['Label'];
}
}
}
}
$form->add(
'config',
IntegrationConfigType::class,
[
'label' => false,
'attr' => [
'class' => 'integration-config-container',
],
'integration' => isset($data['integration'], $integrationObjects[$data['integration']]) ? $integrationObjects[$data['integration']] : null,
'campaigns' => $campaignChoices,
'data' => $data['config'] ?? [],
]
);
$hideClass = (isset($data['campaign_member_status']) && !empty($data['campaign_member_status']['campaign_member_status'])) ? '' : ' hide';
$form->add(
'campaign_member_status',
IntegrationCampaignsType::class,
[
'label' => false,
'attr' => [
'class' => 'integration-campaigns-status'.$hideClass,
],
'campaignContactStatus' => $statusChoices,
'data' => $data['campaign_member_status'] ?? [],
]
);
};
$builder->addEventListener(FormEvents::PRE_SET_DATA, $formModifier);
$builder->addEventListener(FormEvents::PRE_SUBMIT, $formModifier);
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefined(['supported_features']);
$resolver->setDefaults(
[
'supported_features' => 'push_lead',
]
);
}
public function getBlockPrefix(): string
{
return 'integration_list';
}
}

View File

@@ -0,0 +1,77 @@
<?php
namespace Mautic\PluginBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\PasswordType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
use Symfony\Component\Validator\Constraints\Callback;
use Symfony\Component\Validator\Context\ExecutionContextInterface;
/**
* @extends AbstractType<array<mixed>>
*/
class KeysType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options): void
{
$object = $options['integration_object'];
$secretKeys = $object->getSecretKeys();
$requiredKeys = $object->getRequiredKeyFields();
foreach ($options['integration_keys'] as $key => $label) {
$isSecret = in_array($key, $secretKeys);
$required = (isset($requiredKeys[$key]));
// Password fields are going to be blank even if a value exists so only require if a password is not already saved
if ($isSecret && !empty($options['data'][$key])) {
$required = false;
}
$constraints = ($required)
? [
new Callback(
function ($validateMe, ExecutionContextInterface $context) use ($options): void {
if (empty($validateMe) && !empty($options['is_published'])) {
$context->buildViolation('mautic.core.value.required')->addViolation();
}
}
),
] : [];
$type = ($isSecret) ? PasswordType::class : TextType::class;
$builder->add(
$key,
$type,
[
'label' => $label,
'label_attr' => ['class' => 'control-label'],
'attr' => [
'class' => 'form-control',
'placeholder' => (PasswordType::class === $type) ? '**************' : '',
'autocomplete' => 'off',
],
'required' => $required,
'constraints' => $constraints,
'error_bubbling' => false,
]
);
}
$object->appendToForm($builder, $options['data'], 'keys');
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setRequired(['integration_object', 'integration_keys']);
$resolver->setDefined(['secret_keys']);
$resolver->setDefaults(['secret_keys' => [], 'is_published' => true]);
}
public function getBlockPrefix(): string
{
return 'integration_keys';
}
}