Passed
Push — master ( a1fd67...e2e77c )
by Garion
04:50 queued 10s
created

UserFormsRequiredFields::validateRequired()   B

Complexity

Conditions 8
Paths 10

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 11
nc 10
nop 2
dl 0
loc 19
rs 8.4444
c 1
b 0
f 0
1
<?php
2
3
namespace SilverStripe\UserForms\Form;
4
5
use InvalidArgumentException;
6
use SilverStripe\Dev\Debug;
7
use SilverStripe\Forms\FileField;
8
use SilverStripe\Forms\FormField;
9
use SilverStripe\Forms\RequiredFields;
10
use SilverStripe\ORM\ArrayLib;
11
use SilverStripe\UserForms\Model\EditableFormField;
12
13
/**
14
 * An extension of RequiredFields which handles conditionally required fields.
15
 *
16
 * A conditionally required is a field that is required, but can be hidden by display rules.
17
 * When it is visible, (according to the submitted form data) it will be validated as required.
18
 * When it is hidden, it will skip required validation.
19
 *
20
 * Required fields will be validated as usual.
21
 * Conditionally required fields will be validated IF the display rules are satisfied in the submitted dataset.
22
 */
23
class UserFormsRequiredFields extends RequiredFields
24
{
25
    /**
26
     * Allows validation of fields via specification of a php function for
27
     * validation which is executed after the form is submitted.
28
     *
29
     * @param array $data
30
     *
31
     * @return bool
32
     */
33
    public function php($data)
34
    {
35
        $valid = true;
36
        $fields = $this->form->Fields();
37
38
        foreach ($fields as $field) {
39
            $valid = ($field->validate($this) && $valid);
40
        }
41
42
        if (empty($this->required)) {
43
            return $valid;
44
        }
45
46
        foreach ($this->required as $fieldName) {
47
            if (!$fieldName) {
48
                continue;
49
            }
50
51
            // get form field
52
            if ($fieldName instanceof FormField) {
53
                $formField = $fieldName;
54
                $fieldName = $fieldName->getName();
55
            } else {
56
                $formField = $fields->dataFieldByName($fieldName);
57
            }
58
59
            // get editable form field - owns display rules for field
60
            $editableFormField = $this->getEditableFormFieldByName($fieldName);
61
62
            // Validate if the field is displayed
63
            $error =
64
                $editableFormField->isDisplayed($data) &&
65
                $this->validateRequired($formField, $data);
66
67
            // handle error case
68
            if ($formField && $error) {
69
                $this->handleError($formField, $fieldName);
70
                $valid = false;
71
            }
72
        }
73
74
        return $valid;
75
    }
76
77
    /**
78
     * Retrieve an Editable Form field by its name.
79
     * @param string $name
80
     * @return EditableFormField
81
     */
82
    private function getEditableFormFieldByName($name)
83
    {
84
        $field = EditableFormField::get()->filter(['Name' => $name])->first();
85
86
        if ($field) {
0 ignored issues
show
introduced by
$field is of type SilverStripe\ORM\DataObject, thus it always evaluated to true.
Loading history...
87
            return $field;
88
        }
89
90
        // This should happen if form field data got corrupted
91
        throw new InvalidArgumentException(sprintf(
92
            'Could not find EditableFormField with name `%s`',
93
            $name
94
        ));
95
    }
96
97
    /**
98
     * Check if the validation rules for the specified field are met by the provided data.
99
     *
100
     * @note Logic replicated from php() method of parent class `SilverStripe\Forms\RequiredFields`
101
     * @param EditableFormField $field
102
     * @param array $data
103
     * @return bool
104
     */
105
    private function validateRequired(FormField $field, array $data)
106
    {
107
        $error = false;
108
        $fieldName = $field->getName();
109
        // submitted data for file upload fields come back as an array
110
        $value = isset($data[$fieldName]) ? $data[$fieldName] : null;
111
112
        if (is_array($value)) {
113
            if ($field instanceof FileField && isset($value['error']) && $value['error']) {
114
                $error = true;
115
            } else {
116
                $error = (count($value)) ? false : true;
117
            }
118
        } else {
119
            // assume a string or integer
120
            $error = (strlen($value)) ? false : true;
121
        }
122
123
        return $error;
124
    }
125
126
    /**
127
     * Register an error for the provided field.
128
     * @param FormField $formField
129
     * @param string $fieldName
130
     * @return void
131
     */
132
    private function handleError(FormField $formField, $fieldName)
133
    {
134
        $errorMessage = _t(
135
            'SilverStripe\\Forms\\Form.FIELDISREQUIRED',
136
            '{name} is required',
137
            [
138
                'name' => strip_tags(
139
                    '"' . ($formField->Title() ? $formField->Title() : $fieldName) . '"'
140
                )
141
            ]
142
        );
143
144
        if ($msg = $formField->getCustomValidationMessage()) {
145
            $errorMessage = $msg;
146
        }
147
148
        $this->validationError($fieldName, $errorMessage, "required");
149
    }
150
}
151