silverstripe-userforms/code/Form/UserFormsRequiredFields.php
2020-01-14 12:28:04 +13:00

151 lines
4.4 KiB
PHP

<?php
namespace SilverStripe\UserForms\Form;
use InvalidArgumentException;
use SilverStripe\Dev\Debug;
use SilverStripe\Forms\FileField;
use SilverStripe\Forms\FormField;
use SilverStripe\Forms\RequiredFields;
use SilverStripe\ORM\ArrayLib;
use SilverStripe\UserForms\Model\EditableFormField;
/**
* An extension of RequiredFields which handles conditionally required fields.
*
* A conditionally required is a field that is required, but can be hidden by display rules.
* When it is visible, (according to the submitted form data) it will be validated as required.
* When it is hidden, it will skip required validation.
*
* Required fields will be validated as usual.
* Conditionally required fields will be validated IF the display rules are satisfied in the submitted dataset.
*/
class UserFormsRequiredFields extends RequiredFields
{
/**
* Allows validation of fields via specification of a php function for
* validation which is executed after the form is submitted.
*
* @param array $data
*
* @return bool
*/
public function php($data)
{
$valid = true;
$fields = $this->form->Fields();
foreach ($fields as $field) {
$valid = ($field->validate($this) && $valid);
}
if (empty($this->required)) {
return $valid;
}
foreach ($this->required as $fieldName) {
if (!$fieldName) {
continue;
}
// get form field
if ($fieldName instanceof FormField) {
$formField = $fieldName;
$fieldName = $fieldName->getName();
} else {
$formField = $fields->dataFieldByName($fieldName);
}
// get editable form field - owns display rules for field
$editableFormField = $this->getEditableFormFieldByName($fieldName);
// Validate if the field is displayed
$error =
$editableFormField->isDisplayed($data) &&
$this->validateRequired($formField, $data);
// handle error case
if ($formField && $error) {
$this->handleError($formField, $fieldName);
$valid = false;
}
}
return $valid;
}
/**
* Retrieve an Editable Form field by its name.
* @param string $name
* @return EditableFormField
*/
private function getEditableFormFieldByName($name)
{
$field = EditableFormField::get()->filter(['Name' => $name])->first();
if ($field) {
return $field;
}
// This should happen if form field data got corrupted
throw new InvalidArgumentException(sprintf(
'Could not find EditableFormField with name `%s`',
$name
));
}
/**
* Check if the validation rules for the specified field are met by the provided data.
*
* @note Logic replicated from php() method of parent class `SilverStripe\Forms\RequiredFields`
* @param EditableFormField $field
* @param array $data
* @return bool
*/
private function validateRequired(FormField $field, array $data)
{
$error = false;
$fieldName = $field->getName();
// submitted data for file upload fields come back as an array
$value = isset($data[$fieldName]) ? $data[$fieldName] : null;
if (is_array($value)) {
if ($field instanceof FileField && isset($value['error']) && $value['error']) {
$error = true;
} else {
$error = (count($value)) ? false : true;
}
} else {
// assume a string or integer
$error = (strlen($value)) ? false : true;
}
return $error;
}
/**
* Register an error for the provided field.
* @param FormField $formField
* @param string $fieldName
* @return void
*/
private function handleError(FormField $formField, $fieldName)
{
$errorMessage = _t(
'SilverStripe\\Forms\\Form.FIELDISREQUIRED',
'{name} is required',
[
'name' => strip_tags(
'"' . ($formField->Title() ? $formField->Title() : $fieldName) . '"'
)
]
);
if ($msg = $formField->getCustomValidationMessage()) {
$errorMessage = $msg;
}
$this->validationError($fieldName, $errorMessage, "required");
}
}