Skip to content

Commit

Permalink
Add leads 3 support (#30)
Browse files Browse the repository at this point in the history
Co-authored-by: fritzmg <fmg@inspiredminds.at>
  • Loading branch information
koertho and fritzmg authored Apr 2, 2024
1 parent 484a630 commit 84a1da8
Show file tree
Hide file tree
Showing 8 changed files with 141 additions and 68 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/node_modules
/vendor
/composer.lock
.idea
14 changes: 9 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,14 @@
"composer/semver": "^1.0 || ^2.0 || ^3.0",
"doctrine/dbal": "^2.11 || ^3.0",
"jean85/pretty-package-versions": "^1.0 || ^2.0",
"mvo/contao-group-widget": "^1.3"
"mvo/contao-group-widget": "^1.3",
"symfony/service-contracts": "^1.0 || ^2.0 || ^3.0",
"symfony/polyfill-php80": "^1.29"
},
"require-dev": {
"contao/manager-plugin": "^2.0",
"friendsofphp/php-cs-fixer": "^3.0",
"terminal42/contao-leads": "^1.4",
"contao/manager-plugin": "^2.0",
"friendsofphp/php-cs-fixer": "^3.0",
"terminal42/contao-leads": "^1.4 || ^3.0",
"terminal42/contao-mp_forms": "^4.4"
},
"autoload": {
Expand All @@ -51,7 +53,9 @@
"config": {
"allow-plugins": {
"contao-components/installer": true,
"contao/manager-plugin": true
"contao/manager-plugin": true,
"php-http/discovery": false,
"contao-community-alliance/composer-plugin": true
}
}
}
9 changes: 7 additions & 2 deletions src/ContaoManager/Plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
use Contao\ManagerPlugin\Bundle\Config\BundleConfig;
use Contao\ManagerPlugin\Bundle\Parser\ParserInterface;
use InspiredMinds\ContaoFieldsetDuplication\ContaoFieldsetDuplication;
use Terminal42\LeadsBundle\Terminal42LeadsBundle;

/**
* Plugin for the Contao Manager.
Expand All @@ -29,8 +30,12 @@ class Plugin implements BundlePluginInterface
public function getBundles(ParserInterface $parser)
{
return [
BundleConfig::create(ContaoFieldsetDuplication::class)
->setLoadAfter([ContaoCoreBundle::class, 'conditionalformfields', 'leads']),
BundleConfig::create(ContaoFieldsetDuplication::class)->setLoadAfter([
ContaoCoreBundle::class,
'conditionalformfields',
'leads',
Terminal42LeadsBundle::class,
]),
];
}
}
15 changes: 7 additions & 8 deletions src/EventListener/FormHookListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
use Contao\StringUtil;
use Contao\Widget;
use InspiredMinds\ContaoFieldsetDuplication\Helper\FieldHelper;
use MPFormsFormManager;
use Symfony\Component\HttpFoundation\RequestStack;

class FormHookListener
Expand All @@ -38,7 +37,7 @@ public function __construct(RequestStack $requestStack, FieldHelper $fieldHelper

public function onLoadFormField(Widget $widget, string $formId, array $data, Form $form): Widget
{
if ($this->fieldHelper->isFieldsetStart($widget) && $widget->allowDuplication && false === strpos($widget->name, '_duplicate_')) {
if ($this->fieldHelper->isFieldsetStart($widget) && $widget->allowDuplication && !str_contains($widget->name, '_duplicate_')) {
$arrClasses = !empty($widget->class) ? explode(' ', $widget->class) : [];
$arrClasses[] = 'allow-duplication';
$arrClasses[] = 'duplicate-fieldset-'.$widget->id;
Expand Down Expand Up @@ -75,8 +74,8 @@ public function onCompileFormFields(array $fields, $formId, Form $objForm): arra
}

// Get the submitted data from MPForms
if (count($submittedData) === 0 && class_exists(\MPFormsFormManager::class)) {
$manager = new MPFormsFormManager($objForm->id);
if (0 === \count($submittedData) && class_exists(\MPFormsFormManager::class)) {
$manager = new \MPFormsFormManager($objForm->id);
$submittedData = $manager->getDataOfStep($manager->getCurrentStep())['originalPostData'] ?? [];
}

Expand Down Expand Up @@ -198,7 +197,7 @@ public function onStoreFormData(array $set, Form $form): array
$duplicateFieldsData = [];

foreach ($set as $name => $value) {
if (false !== strpos($name, '_duplicate_')) {
if (str_contains($name, '_duplicate_')) {
$duplicateFieldsData[$name] = $value;
continue;
}
Expand Down Expand Up @@ -269,21 +268,21 @@ private function buildFieldsetGroups(array $fields): array
// check if we can process duplicates
if ($this->fieldHelper->isFieldsetStart($field)) {
// check if nested fieldsets are detected and ensure fields are collected
if ($fieldsetGroupStack !== []) {
if ([] !== $fieldsetGroupStack) {
$fieldsetGroups[$fieldsetGroup[0]->id] = $fieldsetGroup;
$fieldsetGroup = [];
}

$fieldsetGroup[] = $field;
$fieldsetGroupStack[] = $field->id;
} elseif ($this->fieldHelper->isFieldsetStop($field)) {
$groupId = \array_pop($fieldsetGroupStack);
$groupId = array_pop($fieldsetGroupStack);
$fieldsetGroup[] = $field;
$fieldsetGroups[$groupId] = $fieldsetGroup;

// Check if nested fieldset are used and restore the out fieldset group
if ($fieldsetGroupStack) {
$fieldsetGroup = $fieldsetGroups[\current($fieldsetGroupStack)];
$fieldsetGroup = $fieldsetGroups[current($fieldsetGroupStack)];
} else {
$fieldsetGroup = [];
}
Expand Down
158 changes: 111 additions & 47 deletions src/EventListener/LeadsListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -12,20 +12,26 @@

namespace InspiredMinds\ContaoFieldsetDuplication\EventListener;

use Codefog\HasteBundle\Formatter;
use Contao\CoreBundle\ServiceAnnotation\Hook;
use Doctrine\DBAL\Connection;
use Haste\Util\Format;
use InspiredMinds\ContaoFieldsetDuplication\Helper\FieldHelper;
use Psr\Container\ContainerInterface;
use Symfony\Contracts\Service\ServiceSubscriberInterface;
use Terminal42\LeadsBundle\Terminal42LeadsBundle;

class LeadsListener
class LeadsListener implements ServiceSubscriberInterface
{
private Connection $connection;
private FieldHelper $fieldHelper;
private ContainerInterface $container;

public function __construct(Connection $connection, FieldHelper $fieldHelper)
public function __construct(ContainerInterface $container, Connection $connection, FieldHelper $fieldHelper)
{
$this->connection = $connection;
$this->fieldHelper = $fieldHelper;
$this->container = $container;
}

/**
Expand All @@ -40,38 +46,130 @@ public function onLoadDataContainer(string $table): void
}
}

/**
* @Hook("processFormData")
*/
public function onProcessFormData(array $postData, array $formConfig, $files): void
{
if (!class_exists(Terminal42LeadsBundle::class) || !$formConfig['leadEnabled']) {
return;
}

$result = $this->connection->createQueryBuilder()->select('id')->from('tl_lead')
->where('form_id=:form_id')
->andWhere('tstamp>:tstamp')
->andWhere('post_data=:post_data')
->setParameter('form_id', $formConfig['id'])
->setParameter('tstamp', time() - 60)
->setParameter('post_data', serialize($postData))
->executeQuery()
->fetchOne()
;

if (false !== $result) {
$this->storeDuplicateFields($formConfig, $postData, $result, 3);
}
}

/**
* @Hook("storeLeadsData")
*/
public function onStoreLeadsData(array $arrPost, array $form, array $arrFiles = null, int $intLead): void
public function onStoreLeadsData(array $arrPost, array $form, ?array $arrFiles, int $intLead): void
{
$this->storeDuplicateFields($form, $arrPost, $intLead);
}

public function getDuplicateFields(array $allFields): array
{
static $duplicateFields = null;

if (!\is_array($duplicateFields)) {
$duplicateFields = [];
$fieldsetGroup = null;

foreach ($allFields as $field) {
if ($this->fieldHelper->isFieldsetStart((object) $field) && $field['allowDuplication'] && $field['leadStore']) {
$fieldsetGroup = $field['name'];

$duplicateFields[$fieldsetGroup] = [
'fieldset' => $field,
'fields' => [],
];

continue;
}

if ($this->fieldHelper->isFieldsetStop((object) $field)) {
$fieldsetGroup = null;
continue;
}

if (null !== $fieldsetGroup) {
$duplicateFields[$fieldsetGroup]['fields'][] = $field;
}
}
}

return $duplicateFields;
}

public static function getSubscribedServices(): array
{
$services = [];

if (class_exists(Formatter::class)) {
$services[Formatter::class] = '?'.Formatter::class;
}

return $services;
}

private function storeDuplicateFields(array $form, array $postData, int $leadId, int $leadsVersion = 1): void
{
$mainIdFieldName = 'master_id';
$mainFieldName = 'leadMaster';

if (3 === $leadsVersion) {
$mainIdFieldName = 'main_id';
$mainFieldName = 'leadMain';
}

// Fetch master form fields
if ($form['leadMaster'] > 0) {
if ($form[$mainFieldName] > 0) {
$leadFields = $this->connection->fetchAllAssociative(
"SELECT f2.*, f1.id AS master_id, f1.name AS postName FROM tl_form_field f1 LEFT JOIN tl_form_field f2 ON f1.leadStore=f2.id WHERE f1.pid=? AND f1.leadStore>0 AND (f2.leadStore=? OR f2.type=? OR f2.type=?) AND f1.invisible=? ORDER BY f2.sorting",
'SELECT f2.*, f1.id AS '.$mainIdFieldName.', f1.name AS postName FROM tl_form_field f1 LEFT JOIN tl_form_field f2 ON f1.leadStore=f2.id WHERE f1.pid=? AND f1.leadStore>0 AND (f2.leadStore=? OR f2.type=? OR f2.type=?) AND f1.invisible=? ORDER BY f2.sorting',
[$form['id'], 1, 'fieldsetStart', 'fieldsetStop', '']
);
} else {
$leadFields = $this->connection->fetchAllAssociative(
"SELECT *, id AS master_id, name AS postName FROM tl_form_field WHERE pid=? AND (leadStore=? OR type=? OR type=?) AND invisible=? ORDER BY sorting",
'SELECT *, id AS '.$mainIdFieldName.', name AS postName FROM tl_form_field WHERE pid=? AND (leadStore=? OR type=? OR type=?) AND invisible=? ORDER BY sorting',
[$form['id'], 1, 'fieldsetStart', 'fieldsetStop', '']
);
}


$time = time();

foreach ($this->getDuplicateFields($leadFields) as $fieldset) {
$fieldsetFields = [];

// Collect the fields
foreach ($fieldset['fields'] as $field) {
foreach ($arrPost as $name => $value) {
foreach ($postData as $name => $value) {
if (preg_match('/^('.preg_quote($field['name']).')(_duplicate_(\d+))?$/', $name, $matches)) {
$index = (int) ($matches[3] ?? 0) + 1;
if (class_exists(Formatter::class) && $this->container->has(Formatter::class)) {
$fieldLabel = $this->container->get(Formatter::class)->dcaLabelFromArray($field);
$fieldValue = $this->container->get(Formatter::class)->dcaValueFromArray($field, $value);
} elseif (class_exists(Format::class)) {
$fieldLabel = Format::dcaLabelFromArray($field);
$fieldValue = Format::dcaValueFromArray($field, $value);
} else {
continue;
}

$fieldsetFields[$index][$field['name']] = [
'label' => Format::dcaLabelFromArray($field),
'value' => Format::dcaValueFromArray($field, $value),
'label' => $fieldLabel,
'value' => $fieldValue,
'raw' => $value,
];
}
Expand All @@ -89,10 +187,10 @@ public function onStoreLeadsData(array $arrPost, array $form, array $arrFiles =

if (\count($fieldsetFields) > 0) {
$this->connection->insert('tl_lead_data', [
'pid' => $intLead,
'pid' => $leadId,
'sorting' => $fieldset['fieldset']['sorting'],
'tstamp' => $time,
'master_id' => $fieldset['fieldset']['master_id'],
$mainIdFieldName => $fieldset['fieldset'][$mainIdFieldName],
'field_id' => $fieldset['fieldset']['id'],
'name' => $fieldset['fieldset']['name'],
'value' => serialize($label),
Expand All @@ -103,42 +201,8 @@ public function onStoreLeadsData(array $arrPost, array $form, array $arrFiles =

// Remove the original fields that were duplicated
foreach ($fieldset['fields'] as $field) {
$this->connection->delete('tl_lead_data', ['pid' => $intLead, 'name' => $field['name']]);
$this->connection->delete('tl_lead_data', ['pid' => $leadId, 'name' => $field['name']]);
}
}
}

public function getDuplicateFields(array $allFields): array
{
static $duplicateFields = null;

if (!\is_array($duplicateFields)) {
$duplicateFields = [];
$fieldsetGroup = null;

foreach ($allFields as $field) {
if ($this->fieldHelper->isFieldsetStart((object) $field) && $field['allowDuplication'] && $field['leadStore']) {
$fieldsetGroup = $field['name'];

$duplicateFields[$fieldsetGroup] = [
'fieldset' => $field,
'fields' => [],
];

continue;
}

if ($this->fieldHelper->isFieldsetStop((object) $field)) {
$fieldsetGroup = null;
continue;
}

if (null !== $fieldsetGroup) {
$duplicateFields[$fieldsetGroup]['fields'][] = $field;
}
}
}

return $duplicateFields;
}
}
4 changes: 2 additions & 2 deletions src/Helper/FieldHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public function isFieldsetStop($field): bool

public function getFieldsetType($field): ?string
{
if (!\is_string($field->type) || false === strpos($field->type, 'fieldset')) {
if (!\is_string($field->type) || !str_contains($field->type, 'fieldset')) {
return null;
}

Expand All @@ -60,6 +60,6 @@ public function getFieldsetType($field): ?string

public function isFieldset($field): bool
{
return false !== strpos($field->type, 'fieldset');
return str_contains($field->type, 'fieldset');
}
}
2 changes: 1 addition & 1 deletion src/Migration/NotificationTokenTemplatesMigration.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public function run(): MigrationResult

foreach (StringUtil::deserialize($field['notificationTokenTemplates'], true) as $key => $template) {
if (is_numeric($key)) {
$key = $key + 1;
++$key;
}

$templates[$key] = $template;
Expand Down
6 changes: 3 additions & 3 deletions src/Resources/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,9 @@ services:
- '@inspiredminds.fieldsetduplication.helper.field'

InspiredMinds\ContaoFieldsetDuplication\EventListener\LeadsListener:
arguments:
- '@database_connection'
- '@inspiredminds.fieldsetduplication.helper.field'
autowire: true
bind:
$fieldHelper: '@inspiredminds.fieldsetduplication.helper.field'

inspiredminds.fieldsetduplication.helper.field:
class: InspiredMinds\ContaoFieldsetDuplication\Helper\FieldHelper
Expand Down

0 comments on commit 84a1da8

Please sign in to comment.