CompoundCopyToChildPass::process()   B
last analyzed

Complexity

Conditions 6
Paths 3

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
dl 0
loc 16
ccs 0
cts 11
cp 0
rs 8.8571
c 0
b 0
f 0
cc 6
eloc 10
nc 3
nop 2
crap 42
1
<?php
2
namespace Boekkooi\Bundle\JqueryValidationBundle\Form\Rule\Processor;
3
4
use Boekkooi\Bundle\JqueryValidationBundle\Form\FormRuleContextBuilder;
5
use Boekkooi\Bundle\JqueryValidationBundle\Form\FormRuleProcessorContext;
6
use Boekkooi\Bundle\JqueryValidationBundle\Form\FormRuleProcessorInterface;
7
use Boekkooi\Bundle\JqueryValidationBundle\Form\Rule\Condition\FieldDependency;
8
use Boekkooi\Bundle\JqueryValidationBundle\Form\Rule\ConstraintRule;
9
use Boekkooi\Bundle\JqueryValidationBundle\Form\Rule\Mapping\RequiredRule;
10
use Boekkooi\Bundle\JqueryValidationBundle\Form\RuleCollection;
11
use Boekkooi\Bundle\JqueryValidationBundle\Form\RuleMessage;
12
use Boekkooi\Bundle\JqueryValidationBundle\Form\Rule\TransformerRule;
13
use Boekkooi\Bundle\JqueryValidationBundle\Form\Util\FormViewRecursiveIterator;
14
use Symfony\Component\Form\Extension\Core\Type\BirthdayType;
15
use Symfony\Component\Form\Extension\Core\Type\DateTimeType;
16
use Symfony\Component\Form\Extension\Core\Type\DateType;
17
use Symfony\Component\Form\Extension\Core\Type\TimeType;
18
use Symfony\Component\Form\FormConfigInterface;
19
use Symfony\Component\Form\FormInterface;
20
use Symfony\Component\Form\FormView;
21
22
/**
23
 * @author Warnar Boekkooi <[email protected]>
24
 */
25
class CompoundCopyToChildPass implements FormRuleProcessorInterface
26
{
27
    const RULE_NAME_GROUP_REQUIRED = 'required_group';
28
29
    protected static $copyForTypes = array(
30
        DateTimeType::class,
31
        TimeType::class,
32
        DateType::class,
33
        BirthdayType::class,
34
    );
35
36
    /**
37
     * @var bool
38
     */
39
    private $useGroupRule;
40
41
    public function __construct($useGroupRule = false)
42
    {
43
        $this->useGroupRule = $useGroupRule;
44
    }
45
46
    public function process(FormRuleProcessorContext $context, FormRuleContextBuilder $formRuleContext)
47
    {
48
        $form = $context->getForm();
49
        $formConfig = $form->getConfig();
50
        if (!$formConfig->getCompound() || $context->getConstraints()->count() === 0) {
51
            return;
52
        }
53
54
        $formView = $context->getView();
55
        $rules = $formRuleContext->get($formView);
56
        if ($rules === null || $rules->count() === 0 || !$this->requiresCopy($form)) {
57
            return;
58
        }
59
60
        $this->registerRulesForChildren($formRuleContext, $formView, $this->getFormRuleMessage($formConfig));
61
    }
62
63
    protected function requiresCopy(FormInterface $form)
64
    {
65
        $type = get_class($form->getConfig()->getType()->getInnerType());
66
67
        return in_array($type, static::$copyForTypes, true);
68
    }
69
70
    private function registerRulesForChildren(FormRuleContextBuilder $formRuleContext, FormView $view, RuleMessage $message = null)
71
    {
72
        // Copy parent rules to the children
73
        $rules = $formRuleContext->get($view);
74
75
        /** @var FormView[]|\RecursiveIteratorIterator $it */
76
        $it = new \RecursiveIteratorIterator(
77
            new FormViewRecursiveIterator($view->getIterator()),
78
            \RecursiveIteratorIterator::LEAVES_ONLY
79
        );
80
81
        /* @var \Boekkooi\Bundle\JqueryValidationBundle\Form\Rule[] $rules */
82
        foreach ($rules as $name => $baseRule) {
83
            if ($this->useGroupRule && $baseRule->name === RequiredRule::RULE_NAME) {
84
                $firstView = null;
85
                $fields = array();
86
                foreach ($it as $childView) {
87
                    if ($firstView === null) {
88
                        $firstView = $childView;
89
                        continue;
90
                    }
91
                    $fields[] = $childView->vars['full_name'];
92
                }
93
94
                $collection = $this->getOrCreateRuleCollection($formRuleContext, $firstView);
95
                $collection->set($name, clone $baseRule);
96
                $collection->set(
97
                    self::RULE_NAME_GROUP_REQUIRED,
98
                    new TransformerRule(self::RULE_NAME_GROUP_REQUIRED, $fields, $message)
99
                );
100
                continue;
101
            }
102
103
            // Prepare a new rule
104
            $rule = clone $baseRule;
105
            foreach ($it as $childView) {
106
                $collection = $this->getOrCreateRuleCollection($formRuleContext, $childView);
107
108
                if ($collection->containsKey($name)) {
109
                    $childRule = $collection[$name];
110
                    $childRule->message = $rule->message;
111
                    $childRule->conditions = $rule->conditions;
112
                    if ($childRule instanceof ConstraintRule && $rule instanceof ConstraintRule) {
113
                        $childRule->groups = array_unique(
114
                            array_merge($childRule->groups, $rule->groups)
115
                        );
116
                    }
117
                } else {
118
                    $collection->set($name, $rule);
119
                }
120
121
                $rule = clone $rule;
122
                $rule->message = $message;
123
                $rule->conditions[] = new FieldDependency($childView->vars['full_name']);
124
            }
125
        }
126
127
        // Clear rules since it's a compound field
128
        $formRuleContext->remove($view);
129
    }
130
131
    protected function getFormRuleMessage(FormConfigInterface $config)
132
    {
133
        // Get correct error message if one is set.
134
        if ($config->hasOption('invalid_message')) {
135
            // TODO support invalid_message_parameters
136
            return new RuleMessage($config->getOption('invalid_message'));
137
        }
138
139
        return null;
140
    }
141
142
    /**
143
     * @param FormRuleContextBuilder $formRuleContext
144
     * @param FormView|string $view
145
     * @return RuleCollection|null
146
     */
147
    private function getOrCreateRuleCollection(FormRuleContextBuilder $formRuleContext, $view)
148
    {
149
        $collection = $formRuleContext->get($view);
150
        if ($collection !== null) {
151
            return $collection;
152
        }
153
        $formRuleContext->add($view, new RuleCollection());
154
155
        return $formRuleContext->get($view);
156
    }
157
}
158