Skip to content

Commit

Permalink
NEW DBField validation
Browse files Browse the repository at this point in the history
  • Loading branch information
emteknetnz committed Sep 24, 2024
1 parent e2e3231 commit 2bf5c61
Show file tree
Hide file tree
Showing 52 changed files with 1,027 additions and 763 deletions.
2 changes: 2 additions & 0 deletions _config/model.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ SilverStripe\Core\Injector\Injector:
class: SilverStripe\ORM\FieldType\DBDecimal
Double:
class: SilverStripe\ORM\FieldType\DBDouble
Email:
class: SilverStripe\ORM\FieldType\DBEmail
Enum:
class: SilverStripe\ORM\FieldType\DBEnum
Float:
Expand Down
3 changes: 2 additions & 1 deletion src/Control/Email/Email.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
use SilverStripe\Core\Injector\Injectable;
use SilverStripe\Core\Injector\Injector;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\FieldType\DBFieldHelper;
use SilverStripe\Model\ArrayData;
use SilverStripe\View\Requirements;
use SilverStripe\View\SSViewer;
Expand Down Expand Up @@ -509,7 +510,7 @@ private function updateHtmlAndTextWithRenderedTemplates(bool $plainOnly = false)
// Plain render fallbacks to using the html render with html tags removed
if (!$plainRender && $htmlRender) {
// call html_entity_decode() to ensure any encoded HTML is also stripped inside ->Plain()
$dbField = DBField::create_field('HTMLFragment', html_entity_decode($htmlRender));
$dbField = DBFieldHelper::create_field('HTMLFragment', html_entity_decode($htmlRender));
$plainRender = $dbField->Plain();
}

Expand Down
1 change: 1 addition & 0 deletions src/Control/RSS/RSSFeed_Entry.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use SilverStripe\Control\Director;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\FieldType\DBFieldHelper;
use SilverStripe\ORM\FieldType\DBHTMLText;
use SilverStripe\Model\ModelData;
use BadMethodCallException;
Expand Down
3 changes: 2 additions & 1 deletion src/Forms/ConfirmedPasswordField.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\DataObjectInterface;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\FieldType\DBFieldHelper;
use SilverStripe\Security\Authenticator;
use SilverStripe\Security\Security;
use SilverStripe\View\HTML;
Expand Down Expand Up @@ -771,6 +772,6 @@ private function getAttributesHTMLForChild(FormField $child): DBField
if (strpos($attributes, 'required="required"') === false && $this->Required()) {
$attributes .= ' required="required" aria-required="true"';
}
return DBField::create_field('HTMLFragment', $attributes);
return DBFieldHelper::create_field('HTMLFragment', $attributes);
}
}
25 changes: 11 additions & 14 deletions src/Forms/EmailField.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

namespace SilverStripe\Forms;

use SilverStripe\Core\Validation\ConstraintValidator;
use Symfony\Component\Validator\Constraints;

/**
* Text input field with validation for correct email format according to RFC 2822.
*/
Expand All @@ -18,32 +21,26 @@ public function Type()
}

/**
* Validates for RFC 2822 compliant email addresses.
*
* @see http://www.regular-expressions.info/email.html
* @see http://www.ietf.org/rfc/rfc2822.txt
*
* @param Validator $validator
*
* @return string
*/
public function validate($validator)
{
$result = true;
$this->value = trim($this->value ?? '');

$pattern = '^[a-z0-9!#$%&\'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&\'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$';

// Escape delimiter characters.
$safePattern = str_replace('/', '\\/', $pattern ?? '');
$result = true;
$message = _t('SilverStripe\\Forms\\EmailField.VALIDATION', 'Please enter an email address');
$validationResult = ConstraintValidator::validate(
$this->value,
new Constraints\Email(message: $message)
);

if ($this->value && !preg_match('/' . $safePattern . '/i', $this->value ?? '')) {
if (!$validationResult->isValid()) {
$validator->validationError(
$this->name,
_t('SilverStripe\\Forms\\EmailField.VALIDATION', 'Please enter an email address'),
'validation'
$validationResult->getMessages()[0]['message'],
);

$result = false;
}

Expand Down
17 changes: 14 additions & 3 deletions src/Forms/FormField.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@
use SilverStripe\Core\Convert;
use SilverStripe\ORM\DataObjectInterface;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\FieldType\DBFieldHelper;
use SilverStripe\ORM\FieldType\DBHTMLText;
use SilverStripe\Core\Validation\ValidationResult;
use SilverStripe\View\AttributesHTML;
use SilverStripe\View\SSViewer;
use SilverStripe\Model\ModelData;
use SilverStripe\Model\ModelFields\ModelField;
use SilverStripe\Model\ModelFields\ModelFieldTrait;
use SilverStripe\Model\ModelFields\StringModelField;

/**
* Represents a field in a form.
Expand All @@ -40,7 +44,7 @@
* including both structure (name, id, attributes, etc.) and state (field value).
* Can be used by for JSON data which is consumed by a front-end application.
*/
class FormField extends RequestHandler
abstract class FormField extends RequestHandler
{
use AttributesHTML;
use FormMessage;
Expand Down Expand Up @@ -87,6 +91,9 @@ class FormField extends RequestHandler
/** @see $schemaDataType */
const SCHEMA_DATA_TYPE_STRUCTURAL = 'Structural';

// TODO: this is wrong, though haven't yet created things like DateTimeModelField
protected string $modelFieldClass = StringModelField::class;

/**
* @var Form
*/
Expand Down Expand Up @@ -344,6 +351,7 @@ public function __construct($name, $title = null, $value = null)

parent::__construct();

// $this->initModelField($name);
$this->setupDefaultClasses();
}

Expand Down Expand Up @@ -929,7 +937,7 @@ public function Field($properties = [])
// Trim whitespace from the result, so that trailing newlines are suppressed. Works for strings and HTMLText values
if (is_string($result)) {
$result = trim($result ?? '');
} elseif ($result instanceof DBField) {
} elseif ($result instanceof ModelField) {
$result->setValue(trim($result->getValue() ?? ''));
}

Expand Down Expand Up @@ -1231,9 +1239,12 @@ protected function extendValidationResult(bool $result, Validator $validator): b
}

/**
* Abstract method each {@link FormField} subclass must implement, determines whether the field
* Method each {@link FormField} subclass can implement, determines whether the field
* is valid or not based on the value.
*
* Subclass methods should call $this->extendValidationResult(true, $validator)
* at the end of the method
*
* @param Validator $validator
* @return bool
*/
Expand Down
8 changes: 4 additions & 4 deletions src/Forms/FormRequestHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -216,10 +216,10 @@ public function httpSubmission($request)
// Action handlers may throw ValidationExceptions.
try {
// Or we can use the Validator attached to the form
$result = $this->form->validationResult();
if (!$result->isValid()) {
return $this->getValidationErrorResponse($result);
}
// $result = $this->form->validationResult();
// if (!$result->isValid()) {
// return $this->getValidationErrorResponse($result);
// }

// First, try a handler method on the controller (has been checked for allowed_actions above already)
$controller = $this->form->getController();
Expand Down
7 changes: 5 additions & 2 deletions src/Forms/GridField/GridField.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use SilverStripe\ORM\DataList;
use SilverStripe\ORM\DataObjectInterface;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\FieldType\DBFieldHelper;
use SilverStripe\Model\List\Filterable;
use SilverStripe\Model\List\Limitable;
use SilverStripe\Model\List\Sortable;
Expand Down Expand Up @@ -382,14 +383,14 @@ public function getCastedValue($value, $castingDefinition)

if (strpos($castingDefinition ?? '', '->') === false) {
$castingFieldType = $castingDefinition;
$castingField = DBField::create_field($castingFieldType, $value);
$castingField = DBFieldHelper::create_field($castingFieldType, $value);

return call_user_func_array([$castingField, 'XML'], $castingParams ?? []);
}

list($castingFieldType, $castingMethod) = explode('->', $castingDefinition ?? '');

$castingField = DBField::create_field($castingFieldType, $value);
$castingField = DBFieldHelper::create_field($castingFieldType, $value);

return call_user_func_array([$castingField, $castingMethod], $castingParams ?? []);
}
Expand Down Expand Up @@ -543,6 +544,8 @@ public function FieldHolder($properties = [])
'footer' => '',
];

$_c = $this->getComponents();

foreach ($this->getComponents() as $item) {
if ($item instanceof GridField_HTMLProvider) {
$fragments = $item->getHTMLFragments($this);
Expand Down
3 changes: 2 additions & 1 deletion src/Forms/GridField/GridFieldLevelup.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use LogicException;
use SilverStripe\ORM\DataObject;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\FieldType\DBFieldHelper;
use SilverStripe\ORM\Hierarchy\Hierarchy;
use SilverStripe\Model\ArrayData;
use SilverStripe\View\HTML;
Expand Down Expand Up @@ -91,7 +92,7 @@ public function getHTMLFragments($gridField)
$linkTag = HTML::createTag('a', $attrs);

$forTemplate = new ArrayData([
'UpLink' => DBField::create_field('HTMLFragment', $linkTag)
'UpLink' => DBFieldHelper::create_field('HTMLFragment', $linkTag)
]);

$template = SSViewer::get_templates_by_class($this, '', __CLASS__);
Expand Down
3 changes: 2 additions & 1 deletion src/Forms/LookupField.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use SilverStripe\Core\ArrayLib;
use SilverStripe\ORM\DataObjectInterface;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\FieldType\DBFieldHelper;

/**
* Read-only complement of {@link MultiSelectField}.
Expand Down Expand Up @@ -58,7 +59,7 @@ public function Field($properties = [])
}

$properties = array_merge($properties, [
'AttrValue' => DBField::create_field('HTMLFragment', $attrValue),
'AttrValue' => DBFieldHelper::create_field('HTMLFragment', $attrValue),
'InputValue' => $inputValue
]);

Expand Down
1 change: 1 addition & 0 deletions src/Forms/SearchableLookupField.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use SilverStripe\Core\ArrayLib;
use SilverStripe\ORM\DataObjectInterface;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\FieldType\DBFieldHelper;
use SilverStripe\Model\List\ArrayList;
use SilverStripe\ORM\DataList;

Expand Down
3 changes: 2 additions & 1 deletion src/Forms/SelectionGroup.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use SilverStripe\Model\List\ArrayList;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\FieldType\DBFieldHelper;
use SilverStripe\View\HTML;

/**
Expand Down Expand Up @@ -91,7 +92,7 @@ public function FieldList()

$itemID = $this->ID() . '_' . (++$count);
$extra = [
"RadioButton" => DBField::create_field('HTMLFragment', HTML::createTag(
"RadioButton" => DBFieldHelper::create_field('HTMLFragment', HTML::createTag(
'input',
[
'class' => 'selector',
Expand Down
3 changes: 2 additions & 1 deletion src/Forms/SingleLookupField.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
use SilverStripe\ORM\DataObjectInterface;
use SilverStripe\Model\List\Map;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\FieldType\DBFieldHelper;

/**
* Read-only complement of {@link DropdownField}.
Expand Down Expand Up @@ -125,7 +126,7 @@ public function Field($properties = [])
}

$properties = array_merge($properties, [
'AttrValue' => DBField::create_field('HTMLFragment', $attrValue),
'AttrValue' => DBFieldHelper::create_field('HTMLFragment', $attrValue),
'InputValue' => $inputValue
]);

Expand Down
4 changes: 4 additions & 0 deletions src/Forms/TextField.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@

namespace SilverStripe\Forms;

use SilverStripe\Model\ModelFields\StringModelField;

/**
* Text input field.
*/
class TextField extends FormField implements TippableFieldInterface
{
protected string $modelFieldClass = StringModelField::class;

/**
* @var int
*/
Expand Down
31 changes: 22 additions & 9 deletions src/Model/ModelData.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@
use SilverStripe\Dev\Debug;
use SilverStripe\Core\ArrayLib;
use SilverStripe\Model\List\ArrayList;
use SilverStripe\ORM\FieldType\DBField;
use SilverStripe\ORM\FieldType\DBHTMLText;
use SilverStripe\Model\ArrayData;
use SilverStripe\View\SSViewer;
use UnexpectedValueException;
use SilverStripe\Model\ModelField;
use SilverStripe\Core\Validation\ValidationResult;

/**
* A ModelData object is any object that can be rendered into a template/view.
Expand Down Expand Up @@ -327,7 +328,7 @@ public function setCustomisedObj(ModelData $object)

/**
* Return the "casting helper" (a piece of PHP code that when evaluated creates a casted value object)
* for a field on this object. This helper will be a subclass of DBField.
* for a field on this object. This helper will be a subclass of ModelField.
*
* @param bool $useFallback If true, fall back on the default casting helper if there isn't an explicit one.
* @return string|null Casting helper As a constructor pattern, and may include arguments.
Expand Down Expand Up @@ -361,7 +362,7 @@ public function castingHelper(string $field, bool $useFallback = true): ?string

/**
* Return the default "casting helper" for use when no explicit casting helper is defined.
* This helper will be a subclass of DBField. See castingHelper()
* This helper will be a subclass of ModelField. See castingHelper()
*/
protected function defaultCastingHelper(string $field): string
{
Expand Down Expand Up @@ -402,7 +403,7 @@ public function escapeTypeForField(string $field): string
{
$class = $this->castingClass($field) ?: $this->config()->get('default_cast');

/** @var DBField $type */
/** @var ModelField $type */
$type = Injector::inst()->get($class, true);
return $type->config()->get('escape_type');
}
Expand Down Expand Up @@ -495,9 +496,9 @@ protected function objCacheClear()
* Get the value of a field on this object, automatically inserting the value into any available casting objects
* that have been specified.
*
* @return object|DBField|null The specific object representing the field, or null if there is no
* @return object|ModelField|null The specific object representing the field, or null if there is no
* property, method, or dynamic data available for that field.
* Note that if there is a property or method that returns null, a relevant DBField instance will
* Note that if there is a property or method that returns null, a relevant ModelField instance will
* be returned.
*/
public function obj(
Expand All @@ -520,7 +521,13 @@ public function obj(
// Load value from record
if ($this->hasMethod($fieldName)) {
$hasObj = true;
$value = call_user_func_array([$this, $fieldName], $arguments ?: []);
// todo: remove try catch block
try {
$value = call_user_func_array([$this, $fieldName], $arguments ?: []);
} catch (Exception $e) {
$x=1;
throw $e;
}
} else {
$hasObj = $this->hasField($fieldName) || ($this->hasMethod("get{$fieldName}") && $this->isAccessibleMethod("get{$fieldName}"));
$value = $this->$fieldName;
Expand Down Expand Up @@ -568,7 +575,7 @@ public function obj(
* A simple wrapper around {@link ModelData::obj()} that automatically caches the result so it can be used again
* without re-running the method.
*
* @return Object|DBField
* @return Object|ModelField
*/
public function cachedCall(string $fieldName, array $arguments = [], ?string $cacheName = null): object
{
Expand Down Expand Up @@ -599,7 +606,13 @@ public function XML_val(string $field, array $arguments = [], bool $cache = fals
return '';
}
// Might contain additional formatting over ->XML(). E.g. parse shortcodes, nl2br()
return $result->forTemplate();
// todo: remove try catch block
try {
return $result->forTemplate();
} catch (Exception $e) {
$x=1;
throw $e;
}
}

/**
Expand Down
Loading

0 comments on commit 2bf5c61

Please sign in to comment.