Skip to content

Commit 112e646

Browse files
committed
DOC Validate DBFields
1 parent 9f14ed6 commit 112e646

File tree

3 files changed

+107
-31
lines changed

3 files changed

+107
-31
lines changed

en/02_Developer_Guides/00_Model/04_Data_Types_and_Casting.md

Lines changed: 33 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -31,33 +31,41 @@ class Player extends DataObject
3131
}
3232
```
3333

34+
Most `DBField` subclasses will be validated using a [`FieldValidator`](api:SilverStripe\Core\Validation\FieldValidation\FieldValidator) subclass which is call as part of the `DataObject::validate()` method. This means that when a value is set on a `DBField` subclass, it will be validated against the constraints of that field. If the value is invalid then a [`ValidationException`](api:SilverStripe\Core\Validation\ValidationException) will be thrown.
35+
3436
## Available types
3537

36-
- `'BigInt'`: An 8-byte signed integer field (see: [DBBigInt](api:SilverStripe\ORM\FieldType\DBBigInt)).
37-
- `'Boolean'`: A boolean field (see: [DBBoolean](api:SilverStripe\ORM\FieldType\DBBoolean)).
38-
- `'Currency'`: A number with 2 decimal points of precision, designed to store currency values. Only supports single currencies (see: [DBCurrency](api:SilverStripe\ORM\FieldType\DBCurrency)).
39-
- `'Date'`: A date field (see: [DBDate](api:SilverStripe\ORM\FieldType\DBDate)).
40-
- `'Datetime'`: A date/time field (see: [DBDatetime](api:SilverStripe\ORM\FieldType\DBDatetime)).
41-
- `'DBClassName'`: A special enumeration for storing class names (see: [DBClassName](api:SilverStripe\ORM\FieldType\DBClassName)).
42-
- `'Decimal'`: A decimal number (see: [DBDecimal](api:SilverStripe\ORM\FieldType\DBDecimal)).
43-
- `'Double'`: A floating point number with double precision (see: [DBDouble](api:SilverStripe\ORM\FieldType\DBDouble)).
44-
- `'Enum'`: An enumeration of a set of strings that can store a single value (see: [DBEnum](api:SilverStripe\ORM\FieldType\DBEnum)).
45-
- `'Float'`: A floating point number (see: [DBFloat](api:SilverStripe\ORM\FieldType\DBFloat)).
46-
- `'Foreignkey'`: A special `Int` field used for foreign keys in `has_one` relationships (see: [DBForeignKey](api:SilverStripe\ORM\FieldType\DBForeignKey)).
47-
- `'HTMLFragment'`: A variable-length string of up to 2MB, designed to store HTML. Doesn't process [shortcodes](/developer_guides/extending/shortcodes/). (see: [DBHTMLText](api:SilverStripe\ORM\FieldType\DBHTMLText)).
48-
- `'HTMLText'`: A variable-length string of up to 2MB, designed to store HTML. Processes [shortcodes](/developer_guides/extending/shortcodes/). (see: [DBHTMLText](api:SilverStripe\ORM\FieldType\DBHTMLText)).
49-
- `'HTMLVarchar'`: A variable-length string of up to 255 characters, designed to store HTML. Can process [shortcodes](/developer_guides/extending/shortcodes/) with additional configuration. (see: [DBHTMLVarchar](api:SilverStripe\ORM\FieldType\DBHTMLVarchar)).
50-
- `'Int'`: A 32-bit signed integer field (see: [DBInt](api:SilverStripe\ORM\FieldType\DBInt)).
51-
- `'Locale'`: A field for storing locales (see: [DBLocale](api:SilverStripe\ORM\FieldType\DBLocale)).
52-
- `'Money'`: Similar to Currency, but with localisation support (see: [DBMoney](api:SilverStripe\ORM\FieldType\DBMoney)).
53-
- `'MultiEnum'`: An enumeration set of strings that can store multiple values (see: [DBMultiEnum](api:SilverStripe\ORM\FieldType\DBMultiEnum)).
54-
- `'Percentage'`: A decimal number between 0 and 1 that represents a percentage (see: [DBPercentage](api:SilverStripe\ORM\FieldType\DBPercentage)).
55-
- `'PolymorphicForeignKey'`: A special ForeignKey class that handles relations with arbitrary class types (see: [DBPolymorphicForeignKey](api:SilverStripe\ORM\FieldType\DBPolymorphicForeignKey)).
56-
- `'PrimaryKey'`: A special type Int field used for primary keys. (see: [DBPrimaryKey](api:SilverStripe\ORM\FieldType\DBPrimaryKey)).
57-
- `'Text'`: A variable-length string of up to 2MB, designed to store raw text (see: [DBText](api:SilverStripe\ORM\FieldType\DBText)).
58-
- `'Time'`: A time field (see: [DBTime](api:SilverStripe\ORM\FieldType\DBTime)).
59-
- `'Varchar'`: A variable-length string of up to 255 characters, designed to store raw text (see: [DBVarchar](api:SilverStripe\ORM\FieldType\DBVarchar)).
60-
- `'Year'`: Represents a single year field (see: [DBYear](api:SilverStripe\ORM\FieldType\DBYear)).
38+
| Field | API link | Description | Validation | API Reference |
39+
| --- | --- | --- | --- | --- |
40+
| `BigInt` | [`DBBigInt`](api:SilverStripe\ORM\FieldType\DBBigInt) | An 8-byte signed integer field | Must be an int between -9223372036854775808 and 9223372036854775807 |
41+
| `Boolean` | [`DBBoolean`](api:SilverStripe\ORM\FieldType\DBBoolean) | A boolean field stored as a tinyint | Must be a boolean |
42+
| `Currency` | [`DBCurrency`](api:SilverStripe\ORM\FieldType\DBCurrency) | A number with 2 decimal points of precision, designed to store currency values | Must be a decimal |
43+
| `Date` | [`DBDate`](api:SilverStripe\ORM\FieldType\DBDate) | A date field | Must be a valid date in `Y-m-d` format |
44+
| `Datetime` | [`DBDatetime`](api:SilverStripe\ORM\FieldType\DBDatetime) | A date/time field | Must be a valid datetime in `Y-m-d H:i:s` format |
45+
| `ClassName` | [`DBClassName`](api:SilverStripe\ORM\FieldType\DBClassName) | A special enumeration for storing class names | Must be a valid FQCN of a `DataObject` subclass |
46+
| `ClassNameVarchar` | [`DBClassNameVarchar`](api:SilverStripe\ORM\FieldType\DBClassNameVarchar) | A special enumeration for storing class names in a `Varchar` field | Must be a valid FQCN of a `DataObject` subclass |
47+
| `Decimal` | [`DBDecimal`](api:SilverStripe\ORM\FieldType\DBDecimal) | A decimal number | Must be a decimal. |
48+
| `Double` | [`DBDouble`](api:SilverStripe\ORM\FieldType\DBDouble) | A floating point number with double precision | Must be numeric |
49+
| `Email` | [`DBEmail`](api:SilverStripe\ORM\FieldType\DBEmail) | An email field | Must be a valid email address |
50+
| `Enum` | [`DBEnum`](api:SilverStripe\ORM\FieldType\DBEnum) | An enumeration of a set of strings that can store a single value | Must be one of the defined values |
51+
| `Float` | [`DBFloat`](api:SilverStripe\ORM\FieldType\DBFloat) | A floating point number | Must be numeric |
52+
| `ForeignKey` | [`DBForeignKey`](api:SilverStripe\ORM\FieldType\DBForeignKey) | A special `Int` field used for foreign keys in `has_one` relationships | Must be an int |
53+
| `HTMLFragment` | [`DBHTMLText`](api:SilverStripe\ORM\FieldType\DBHTMLText) | A variable-length string of up to 2MB, designed to store HTML. Doesn't process [shortcodes](/developer_guides/extending/shortcodes/) | Must be a string |
54+
| `HTMLText` | [`DBHTMLText`](api:SilverStripe\ORM\FieldType\DBHTMLText) | A variable-length string of up to 2MB, designed to store HTML. Processes [shortcodes](/developer_guides/extending/shortcodes/) | Must be a string |
55+
| `HTMLVarchar` | [`DBHTMLVarchar`](api:SilverStripe\ORM\FieldType\DBHTMLVarchar) | A variable-length string of up to 255 characters, designed to store HTML. Can process [shortcodes](/developer_guides/extending/shortcodes/) with additional configuration | String must not be longer than specified length |
56+
| `Int` | [`DBInt`](api:SilverStripe\ORM\FieldType\DBInt) | A 32-bit signed integer field | Must be an int between -2147483648 and 2147483647 |
57+
| `IP` | [`DBIp`](api:SilverStripe\ORM\FieldType\DBIp) | An IP field | Must be a valid IP address, either IPv4 or IPv6 |
58+
| `Locale` | [`DBLocale`](api:SilverStripe\ORM\FieldType\DBLocale) | A field for storing locales | Must be a valid locale |
59+
| `Money` | [`DBMoney`](api:SilverStripe\ORM\FieldType\DBMoney) | A localised money field with a 3 character currency component, and an amount component. | Currency string must not be greater than 3 characters, amount must be a decimal |
60+
| `MutliEnum` | [`DBMultiEnum`](api:SilverStripe\ORM\FieldType\DBMultiEnum) | An enumeration set of strings that can store multiple values | Must be one of the allowable values |
61+
| `Percentage` | [`DBPercentage`](api:SilverStripe\ORM\FieldType\DBPercentage) | A decimal number between 0 and 1 that represents a percentage | Must be a decimal between 0 and 1 |
62+
| `DBPolymorphicForeignKey` | [`DBPolymorphicForeignKey`](api:SilverStripe\ORM\FieldType\DBPolymorphicForeignKey) | A special ForeignKey class that handles relations with arbitrary class types | Must be an int |
63+
| `PrimaryKey` | [`DBPrimaryKey`](api:SilverStripe\ORM\FieldType\DBPrimaryKey) | A special type Int field used for primary keys | Must be an int |
64+
| `Text` | [`DBText`](api:SilverStripe\ORM\FieldType\DBText) | A variable-length string of up to 2MB, designed to store raw text | Must be a string |
65+
| `Time` | [`DBTime`](api:SilverStripe\ORM\FieldType\DBTime) | A time field | Must be a valid time in `H:i:s` format |
66+
| `URL` | [`DBUrl`](api:SilverStripe\ORM\FieldType\DBUrl) | A URL field | Must be a valid URL |
67+
| `Varchar` | [`DBVarchar`](api:SilverStripe\ORM\FieldType\DBVarchar) | A variable-length string of up to 255 characters, designed to store raw text | String must not be longer than specified length |
68+
| `Year` | [`DBYear`](api:SilverStripe\ORM\FieldType\DBYear) | Represents a single year field | Must be a valid year between 1901 and 2155 |
6169

6270
See the [API documentation](api:SilverStripe\ORM\FieldType) for a full list of available data types. You can define your own [`DBField`](api:SilverStripe\ORM\FieldType\DBField) instances if required as well.
6371

en/02_Developer_Guides/00_Model/09_Validation.md

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,11 @@ Traditionally, validation in Silverstripe CMS has been mostly handled through [f
3939

4040
Most validation constraints are actually data constraints which belong on the model. Silverstripe CMS provides the
4141
[`DataObject::validate()`](api:SilverStripe\ORM\DataObject::validate()) method for this purpose. The `validate()` method is
42-
called any time the `write()` method is called, before the `onBeforeWrite()` extension hook.
43-
44-
By default, there is no validation - objects are always valid! However, you can override this method in your `DataObject`
42+
called any time the `write()` method is called. Implement this method in your `DataObject`
4543
sub-classes to specify custom validation, or use the `updateValidate()` extension hook through an [Extension](api:SilverStripe\Core\Extension).
4644

4745
Invalid objects won't be able to be written - a [`ValidationException`](api:SilverStripe\Core\Validation\ValidationException) will be thrown and no write will occur.
4846

49-
Ideally you should call `validate()` in your own application to test that an object is valid before attempting a
50-
write, and respond appropriately if it isn't.
51-
5247
The return value of `validate()` is a [`ValidationResult`](api:SilverStripe\Core\Validation\ValidationResult) object.
5348

5449
```php
@@ -82,6 +77,16 @@ class MyObject extends DataObject
8277
}
8378
```
8479

80+
## DBField validation
81+
82+
[`DBField`](api:SilverStripe\ORM\FieldType\DBField) is the base class for all database fields in Silverstripe CMS. For instance when you defined `'MyField' => 'Varchar(255)'` in your [`DataObject`](api:SilverStripe\ORM\DataObject) subclass, the `MyField` property would be an instance of [`DBVarchar`](api:SilverStripe\ORM\FieldType\DBVarchar).
83+
84+
Most `DBField` subclasses will have their values validated as part of `DataObject::validate()`. This means that when a value is set on a `DBField` subclass, it will be validated against the constraints of that field. Field validation is called as part of `DataObject::validate()` which itself is called as part of [`DataObject::write()`](api:SilverStripe\ORM\DataObject::write()). If a value is invalid then a [`ValidationException`](api:SilverStripe\ORM\Validation\ValidationException) will be thrown.
85+
86+
For example, if you have a `Varchar(64)`, and you try to set a value longer than 64 characters, a validation exception will be thrown.
87+
88+
A full list of DBField subclasses and their validation rules can be found in [Data Types and Casting](data_types_and_casting).
89+
8590
## API documentation
8691

8792
- [DataObject](api:SilverStripe\ORM\DataObject)

en/08_Changelogs/6.0.0.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ title: 6.0.0 (unreleased)
77
## Overview
88

99
- [Features and enhancements](#features-and-enhancements)
10+
- [Validation added to DBFields](#dbfield-validation)
1011
- [Changes to `sake`, `BuildTask`, CLI interaction in general](#cli-changes)
1112
- [Read-only replica database support](#db-read-only-replicas)
1213
- [Run `CanonicalURLMiddleware` in all environments by default](#url-middleware)
@@ -39,6 +40,67 @@ title: 6.0.0 (unreleased)
3940

4041
## Features and enhancements
4142

43+
### Validation added to `DBField`s {#dbfield-validation}
44+
45+
[`DBField`](api:SilverStripe\ORM\FieldType\DBField) is the base class for all database fields in Silverstripe CMS. For instance when you defined `'MyField' => 'Varchar(255)'` in your [`DataObject`](api:SilverStripe\ORM\DataObject) subclass, the `MyField` property would be an instance of [`DBVarchar`](api:SilverStripe\ORM\FieldType\DBVarchar).
46+
47+
Validation has added been to most `DBField` subclasses. This means that when a value is set on a `DBField` subclass, it will be validated against the constraints of that field. This field validation is called as part of [`DataObject::validate()`](api:SilverStripe\ORM\DataObject::validate()) which itself is called as part of [`DataObject::write()`](api:SilverStripe\ORM\DataObject::write()). If a value is invalid then a [`ValidationException`](api:SilverStripe\ORM\Validation\ValidationException) will be thrown.
48+
49+
For example, if you have a `Varchar(64)`, and you try to set a value longer than 64 characters, a exception will now be thrown. Previously, the value would be truncated to 64 characters and saved to the database.
50+
51+
The validation is added through subclasses of the new [`FieldValidator`](api:SilverStripe\Core\Validation\FieldValidation\FieldValidator) abstract class, for instance the [`StringFieldValidator`](api:SilverStripe\Core\Validation\FieldValidation\StringFieldValidator) is used to validate [`DBVarchar`](api:SilverStripe\ORM\FieldType\DBVarchar).
52+
53+
Note that this new `DBField` validation is independent of the existing CMS form field validation that uses methods such as [`FormField::validate()`](api:SilverStripe\Forms\FormField::validate()) and [`DataObject::getCMSCompositeValidator()`](api:SilverStripe\ORM\DataObject::getCMSCompositeValidator()).
54+
55+
Updates have been made to some `setValue()` methods of `DBField` subclasses to convert the value to the correct type before validating it.
56+
57+
- [`DBBoolean`](api:SilverStripe\ORM\FieldType\DBBoolean) uses the `tinyint` data type and retains the legacy behaviour of converting `true/'true'/'t'/'1'` to `1`, `false/'false'/'f'/'0'` to `0`.
58+
- [`DBDecimal`](api:SilverStripe\ORM\FieldType\DBDecimal) will convert numeric strings as well as integers to floats.
59+
- [`DBForeignKey`](api:SilverStripe\ORM\FieldType\DBForeignKey) will convert a blank string to 0.
60+
- [`DBInt`](api:SilverStripe\ORM\FieldType\DBInt) will convert integer like strings to integers.
61+
- [`DBYear`](api:SilverStripe\ORM\FieldType\DBYear) will convert integer like strings to integers. Also shorthand years are converted to full years (e.g. "24" becomes "2024").
62+
63+
In most cases though, the correct scalar type must now be used. For instance it is no longer possible to set an integer value on a `DBVarchar` field. You must use a string.
64+
65+
Some new DBField subclasses have been added which will provide validation for specific types of data:
66+
67+
- [`DBEmail`](api:SilverStripe\ORM\FieldType\DBEmail) for email addresses.
68+
- [`DBIp`](api:SilverStripe\ORM\FieldType\DBIp) for IP addresses.
69+
- [`DBUrl`](api:SilverStripe\ORM\FieldType\DBUrl) for URLs.
70+
71+
To use these new field types, simply define them in a DataObject subclass:
72+
73+
```php
74+
// app/src/Pages/MyPage.php
75+
namespace App\Pages;
76+
77+
use SilverStripe\CMS\Model\SiteTree;
78+
79+
class MyPage extends SiteTree
80+
{
81+
private static array $db = [
82+
// Values will be validated as an email address
83+
'MyEmail' => 'Email',
84+
// Values will be validated as an IP address
85+
'MyIP' => 'IP',
86+
// Values will be validated as a URL
87+
'MyURL' => 'URL',
88+
];
89+
}
90+
```
91+
92+
> [!WARNING]
93+
> If you have an existing project that uses Varchar fields for email addresses, IP addresses, or URLs, and you switch to using one of the new DBField types, be aware that some of the values in the database may fail validation the next time they are saved which could cause issues for CMS editors.
94+
> You may wish to create a [`BuildTask`](api:SilverStripe\Dev\BuildTask) that calls [`DataObject::validate()`](api:SilverStripe\ORM\DataObject::validate()) on all affected records.
95+
96+
While we have tried to match the validation rules up to what would already have been stored in the database, there is a chance you'll find yourself with pre-existing data which doesn't meet the validation rules, and which therefore causes validation exceptions to be thrown the next time you try to save those records.
97+
98+
If that happens, you may be able to resolve it with one of the following solutions:
99+
100+
- If there is a form field for that database column, update the value in the form to a valid value before saving the record.
101+
- Write a `BuildTask` that updates any invalid values in your database.
102+
- While it's generally not recommended, you have the option of disabling validation via the [`DataObject.validation_enabled`](api:SilverStripe\ORM\DataObject->validation_enabled) configuration property.
103+
42104
### Changes to `sake`, `BuildTask`, and CLI interaction in general {#cli-changes}
43105

44106
Until now, running `sake` on the command line has executed a simulated HTTP request to your Silverstripe CMS project, using the routing and controllers that your web application uses to handle HTTP requests. This resulted in both a non-standard CLI experience and added confusion about when an [`HTTPRequest`](api:SilverStripe\Control\HTTPRequest) actually represented an HTTP request.
@@ -787,6 +849,7 @@ As part of these changes [`ArrayList::find()`](api:SilverStripe\Model\List\Array
787849
- [`FieldList`](api:SilverStripe\Forms\FieldList) is now strongly typed. Methods that previously allowed any iterable variables to be passed, namely [`FieldList::addFieldsToTab()`](api:SilverStripe\Forms\FieldList::addFieldsToTab()) and [`FieldList::removeFieldsFromTab()`](api:SilverStripe\Forms\FieldList::removeFieldsFromTab()), now require an array to be passed instead.
788850
- [`BaseElement::getDescription()`](api:DNADesign\Elemental\Models\BaseElement::getDescription()) has been removed. If you had implemented this method in your custom elemental blocks, either set the [`description`](api:DNADesign\Elemental\Models\BaseElement->description) configuration property or override the [`getTypeNice()`](api:DNADesign\Elemental\Models\BaseElement::getTypeNice()) method.
789851
- [`DataExtension`](api:SilverStripe\ORM\DataExtension), [`SiteTreeExtension`](api:SilverStripe\CMS\Model\SiteTreeExtension), and [`LeftAndMainExtension`](api:SilverStripe\Admin\LeftAndMainExtension) have been removed. If you subclass any of these classes, you must now subclass [`Extension`](api:SilverStripe\Core\Extension) instead.
852+
- [`DBCurrency`](api:SilverStripe\ORM\FieldType\DBCurrency) will no longer parse numeric values contained in a string when calling `setValue()`. For instance "this is 50.29 dollars" will no longer be converted to "$50.29", instead its value will remain as "this is 50.29 dollars" and it will throw a validation exception if attempted to be written to the database.
790853

791854
## Other changes
792855

0 commit comments

Comments
 (0)