<?php declare(strict_types=1);
namespace MoorlFormsClassic\Core\Subscriber;
use MoorlForms\Core\Content\Element\ElementDataStruct;
use MoorlForms\Core\Event\ValidateFormEvent;
use MoorlForms\Core\Service\DataStructFactory;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class ValidateFormSubscriber implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
ValidateFormEvent::class => 'processConditions',
];
}
public function processConditions(ValidateFormEvent $event): void
{
$dataStruct = $event->getForm()->getDataStruct();
$this->_walkTree(
$dataStruct->getElements(),
$dataStruct->getFlattenElements()
);
}
private function _walkTree(array $elements, array $flattenElements): void
{
if (empty($elements)) {
return;
}
/** @var ElementDataStruct $element */
foreach ($elements as $element) {
if (DataStructFactory::_enrichCallback($element, function ($elements) use ($flattenElements) {
self::_walkTree($elements, $flattenElements);
})) {continue;}
if ($element->getConditions()) {
foreach ($element->getConditions() as $condition) {
try {
$path = $condition['name'];
$match = $this->_compare(
$condition['value'],
$flattenElements[$path]->getValue(),
$condition['type']
);
} catch (\Exception $exception) {
$match = false;
}
if (!$match) {
$element->unset();
}
}
}
$this->_walkTree($element->getChildren(), $flattenElements);
}
}
private function _compare($value1, $value2, $type): bool
{
// Prevent misconfiguration
if (!$value1 || !$value2) {
return true;
}
if (!is_array($value1)) {
$value1 = explode(";", $value1);
}
if (!is_array($value2)) {
$value2 = explode(";", $value2);
}
switch ($type) {
case 'is':
return !!array_filter($value1, function ($element) use ($value2) {
return in_array($element, $value2);
});
case 'not':
return !!array_filter($value1, function ($element) use ($value2) {
return !in_array($element, $value2);
});
case 'gt':
return (float) $value1[0] > (float) $value2[0];
case 'lt':
return (float) $value1[0] < (float) $value2[0];
case 'gte':
return (float) $value1[0] >= (float) $value2[0];
case 'lte':
return (float) $value1[0] <= (float) $value2[0];
case 'contains':
return !!array_filter($value1, function ($element) use ($value2) {
if (is_array($element)) {
return !in_array($element, $value2);
} else {
return str_contains((string) $value2[0], $element);
}
});
}
return false;
}
}