Skip to content

Commit

Permalink
DOC Validate DBFields
Browse files Browse the repository at this point in the history
  • Loading branch information
emteknetnz committed Oct 14, 2024
1 parent 5c3a069 commit 0e8d5ae
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 35 deletions.
58 changes: 33 additions & 25 deletions en/02_Developer_Guides/00_Model/04_Data_Types_and_Casting.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,33 +31,41 @@ class Player extends DataObject
}
```

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 you set a value on a `DBField` subclass, it will be validated against the constraints of that field. If a value is invalid, a [`ValidationException`](api:SilverStripe\Core\Validation\ValidationException) will be thrown.

## Available types

- `'BigInt'`: An 8-byte signed integer field (see: [DBBigInt](api:SilverStripe\ORM\FieldType\DBBigInt)).
- `'Boolean'`: A boolean field (see: [DBBoolean](api:SilverStripe\ORM\FieldType\DBBoolean)).
- `'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)).
- `'Date'`: A date field (see: [DBDate](api:SilverStripe\ORM\FieldType\DBDate)).
- `'Datetime'`: A date/time field (see: [DBDatetime](api:SilverStripe\ORM\FieldType\DBDatetime)).
- `'DBClassName'`: A special enumeration for storing class names (see: [DBClassName](api:SilverStripe\ORM\FieldType\DBClassName)).
- `'Decimal'`: A decimal number (see: [DBDecimal](api:SilverStripe\ORM\FieldType\DBDecimal)).
- `'Double'`: A floating point number with double precision (see: [DBDouble](api:SilverStripe\ORM\FieldType\DBDouble)).
- `'Enum'`: An enumeration of a set of strings that can store a single value (see: [DBEnum](api:SilverStripe\ORM\FieldType\DBEnum)).
- `'Float'`: A floating point number (see: [DBFloat](api:SilverStripe\ORM\FieldType\DBFloat)).
- `'Foreignkey'`: A special `Int` field used for foreign keys in `has_one` relationships (see: [DBForeignKey](api:SilverStripe\ORM\FieldType\DBForeignKey)).
- `'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)).
- `'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)).
- `'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)).
- `'Int'`: A 32-bit signed integer field (see: [DBInt](api:SilverStripe\ORM\FieldType\DBInt)).
- `'Locale'`: A field for storing locales (see: [DBLocale](api:SilverStripe\ORM\FieldType\DBLocale)).
- `'Money'`: Similar to Currency, but with localisation support (see: [DBMoney](api:SilverStripe\ORM\FieldType\DBMoney)).
- `'MultiEnum'`: An enumeration set of strings that can store multiple values (see: [DBMultiEnum](api:SilverStripe\ORM\FieldType\DBMultiEnum)).
- `'Percentage'`: A decimal number between 0 and 1 that represents a percentage (see: [DBPercentage](api:SilverStripe\ORM\FieldType\DBPercentage)).
- `'PolymorphicForeignKey'`: A special ForeignKey class that handles relations with arbitrary class types (see: [DBPolymorphicForeignKey](api:SilverStripe\ORM\FieldType\DBPolymorphicForeignKey)).
- `'PrimaryKey'`: A special type Int field used for primary keys. (see: [DBPrimaryKey](api:SilverStripe\ORM\FieldType\DBPrimaryKey)).
- `'Text'`: A variable-length string of up to 2MB, designed to store raw text (see: [DBText](api:SilverStripe\ORM\FieldType\DBText)).
- `'Time'`: A time field (see: [DBTime](api:SilverStripe\ORM\FieldType\DBTime)).
- `'Varchar'`: A variable-length string of up to 255 characters, designed to store raw text (see: [DBVarchar](api:SilverStripe\ORM\FieldType\DBVarchar)).
- `'Year'`: Represents a single year field (see: [DBYear](api:SilverStripe\ORM\FieldType\DBYear)).
| Field | Description | Validation | API Reference |
| --- | --- | --- | --- |
| `BigInt` | An 8-byte signed integer field | Must be an int between -9223372036854775808 and 9223372036854775807 | [`DBBigInt`](api:SilverStripe\ORM\FieldType\DBBigInt) |
| `Boolean` | A boolean field stored as a tinyint | Must be `1` or `0`, though `true` and `false` will be automatically converted | [`DBBoolean`](api:SilverStripe\ORM\FieldType\DBBoolean) |
| `Currency` | A number with 2 decimal points of precision, designed to store currency values | Must be a decimal | [`DBCurrency`](api:SilverStripe\ORM\FieldType\DBCurrency) |
| `Date` | A date field | Must be a valid date in `Y-m-d` format | [`DBDate`](api:SilverStripe\ORM\FieldType\DBDate) |
| `Datetime` | A date/time field | Must be a valid date in `Y-m-d H:i:s` format | [`DBDatetime`](api:SilverStripe\ORM\FieldType\DBDatetime) |
| `DBClassName` | A special enumeration for storing class names | Must be a valid subclass name | [`DBClassName`](api:SilverStripe\ORM\FieldType\DBClassName) |
| `DBClassNameVarchar` | A special enumeration for storing class names in a `Varchar` field | Must be a valid subclass name | [`DBClassNameVarchar`](api:SilverStripe\ORM\FieldType\DBClassNameVarchar) |
| `Decimal` | A decimal number | Must be a decimal | [`DBDecimal`](api:SilverStripe\ORM\FieldType\DBDecimal) |
| `Double` | A floating point number with double precision | Must Not validated | [`DBDouble`](api:SilverStripe\ORM\FieldType\DBDouble) |
| `Email` | An email field | Must be a valid email address | [`DBEmail`](api:SilverStripe\ORM\FieldType\DBEmail) |
| `Enum` | An enumeration of a set of strings that can store a single value | Must be one of the defined values | [`DBEnum`](api:SilverStripe\ORM\FieldType\DBEnum) |
| `Float` | A floating point number | Not validated | [`DBFloat`](api:SilverStripe\ORM\FieldType\DBFloat) |
| `ForeignKey` | A special `Int` field used for foreign keys in `has_one` relationships | Must be an int | [`DBForeignKey`](api:SilverStripe\ORM\FieldType\DBForeignKey) |
| `HTMLFragment` | A variable-length string of up to 2MB, designed to store HTML. Doesn't process [shortcodes](/developer_guides/extending/shortcodes/) | Not validated | [`DBHTMLText`](api:SilverStripe\ORM\FieldType\DBHTMLText) |
| `HTMLText` | A variable-length string of up to 2MB, designed to store HTML. Processes [shortcodes](/developer_guides/extending/shortcodes/) | Not validated | [`DBHTMLText`](api:SilverStripe\ORM\FieldType\DBHTMLText) |
| `HTMLVarchar` | 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 | [`DBHTMLVarchar`](api:SilverStripe\ORM\FieldType\DBHTMLVarchar) |
| `Int` | A 32-bit signed integer field | Must be an int between -2147483648 and 2147483647 | [`DBInt`](api:SilverStripe\ORM\FieldType\DBInt) |
| `IP` | An IP field | Must be a valid IP address, either IPv4 or IPv6 | [`DBIp`](api:SilverStripe\ORM\FieldType\DBIp) |
| `Locale` | A field for storing locales | Must be a valid locale | [`DBLocale`](api:SilverStripe\ORM\FieldType\DBLocale) |
| `Money` | Similar to Currency, but with localisation support | Currency string must not be greater than 4 characters, amount must be a decimal | [`DBMoney`](api:SilverStripe\ORM\FieldType\DBMoney) |
| `MultiEnum` | An enumeration set of strings that can store multiple values | Must be one of the defined values | [`DBMultiEnum`](api:SilverStripe\ORM\FieldType\DBMultiEnum) |
| `Percentage` | A decimal number between 0 and 1 that represents a percentage | Must be a decimal between 0 and 1 | [`DBPercentage`](api:SilverStripe\ORM\FieldType\DBPercentage) |
| `PolymorphicForeignKey` | A special ForeignKey class that handles relations with arbitrary class types | Must be an int | [`DBPolymorphicForeignKey`](api:SilverStripe\ORM\FieldType\DBPolymorphicForeignKey) |
| `PrimaryKey` | A special type Int field used for primary keys | Must be an int | [`DBPrimaryKey`](api:SilverStripe\ORM\FieldType\DBPrimaryKey) |
| `Text` | A variable-length string of up to 2MB, designed to store raw text | Not validated | [`DBText`](api:SilverStripe\ORM\FieldType\DBText) |
| `Time` | A time field | Must be a valid time in `H:i:s` format | [`DBTime`](api:SilverStripe\ORM\FieldType\DBTime) |
| `URL` | A URL field | Must be a valid URL | [`DBUrl`](api:SilverStripe\ORM\FieldType\DBUrl) |
| `Varchar` | A variable-length string of up to 255 characters, designed to store raw text | String must not be longer than specified length | [`DBVarchar`](api:SilverStripe\ORM\FieldType\DBVarchar) |
| `Year` | Represents a single year field | Must be a valid year between 1901 and 2155 | [`DBYear`](api:SilverStripe\ORM\FieldType\DBYear) |

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.

Expand Down
17 changes: 11 additions & 6 deletions en/02_Developer_Guides/00_Model/09_Validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,11 @@ Traditionally, validation in Silverstripe CMS has been mostly handled through [f

Most validation constraints are actually data constraints which belong on the model. Silverstripe CMS provides the
[`DataObject::validate()`](api:SilverStripe\ORM\DataObject::validate()) method for this purpose. The `validate()` method is
called any time the `write()` method is called, before the `onBeforeWrite()` extension hook.

By default, there is no validation - objects are always valid! However, you can override this method in your `DataObject`
called any time the `write()` method is called. Implement this method in your `DataObject`
sub-classes to specify custom validation, or use the `updateValidate()` extension hook through an [Extension](api:SilverStripe\Core\Extension).

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

Ideally you should call `validate()` in your own application to test that an object is valid before attempting a
write, and respond appropriately if it isn't.

The return value of `validate()` is a [`ValidationResult`](api:SilverStripe\Core\Validation\ValidationResult) object.

```php
Expand Down Expand Up @@ -82,6 +77,16 @@ class MyObject extends DataObject
}
```

## DBField validation

[`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).

Most `DBField` subclasses will have their values validated as part of `DataObject::validate()`. This means that when you set a value on a `DBField` subclass, it will be validated against the constraints of that 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, a [`ValidationException`](api:SilverStripe\ORM\Validation\ValidationException) will be thrown.

For example, if you have a `Varchar(64)`, and you try to set a value longer than 64 characters, an exception will be thrown.

A full list of DBField subclasses and their validation rules can be found in [Data Types and Casting](data_types_and_casting).

## API documentation

- [DataObject](api:SilverStripe\ORM\DataObject)
Expand Down
53 changes: 53 additions & 0 deletions en/08_Changelogs/6.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ title: 6.0.0 (unreleased)
## Overview

- [Features and enhancements](#features-and-enhancements)
- [Validation added to DBFields](#dbfield-validation)
- [Changes to `sake`, `BuildTask`, CLI interaction in general](#cli-changes)
- [Run `CanonicalURLMiddleware` in all environments by default](#url-middleware)
- [Changes to default cache adapters](#caching)
Expand Down Expand Up @@ -35,6 +36,57 @@ title: 6.0.0 (unreleased)

## Features and enhancements

### Validation added to `DBField`s {#dbfield-validation}

[`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).

Validation has been to most `DBField` subclasses. This means that when you set a value on a `DBField` subclass, it will be validated against the constraints of that field. This validation is called as part of [`DataObjectDataObject::validate()`](api:SilverStripe\ORM\DataObjectDataObject::validate()) which itself is called as part of [`DataObject::write()`](api:SilverStripe\ORM\DataObject::write()). If a value is invalid, a [`ValidationException`](api:SilverStripe\ORM\Validation\ValidationException) will be thrown.

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.

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).

Note that this new `DBField` validation is independent of the existing CMS form field validation that happens in [`FormField::validate()`](api:SilverStripe\Forms\FormField::validate()) and [`DataObject::getCMSCompositeValidator()`](api:SilverStripe\ORM\DataObject::getCMSCompositeValidator()).

Updates have been made to some `setValue()` methods of `DBField` subclasses to convert the value to the correct type before validating it.

- [`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`.
- [`DBDecimal`](api:SilverStripe\ORM\FieldType\DBDecimal) will convert numeric strings as well as integers to floats.
- [`DBEnum`](api:SilverStripe\ORM\FieldType\DBEnum) will convert empty values to the default enum value.
- [`DBForeignKey`](api:SilverStripe\ORM\FieldType\DBForeignKey) will convert a blank string to 0.
- [`DBInt`](api:SilverStripe\ORM\FieldType\DBInt) will convert integer like strings to integers.
- [`DBString`](api:SilverStripe\ORM\FieldType\DBString) will convert null values to an empty string. Note that when persisted in the database blank strings are stored as `null` in most instances.
- [`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").

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.

Some new DBField subclasses have been added which will provide validation for specific types of data:

- [`DBEmail`](api:SilverStripe\ORM\FieldType\DBEmail) for email addresses.
- [`DBIp`](api:SilverStripe\ORM\FieldType\DBIp) for IP addresses.
- [`DBUrl`](api:SilverStripe\ORM\FieldType\DBUrl) for URLs.

To use these new field types, you can define them in your DataObject subclass like so:

```php
// app/src/Pages/MyPage.php
namespace App\Pages;

use SilverStripe\CMS\Model\SiteTree;

class MyPage extends SiteTree
{
private static array $db = [
// Values will be validated as an email address
'MyEmail' => 'Email',
// Values will be validated as an IP address
'MyIp' => 'IP',
// Values will be validated as a URL
'MyUrl' => 'Url',
];
}
```

### Changes to `sake`, `BuildTask`, and CLI interaction in general {#cli-changes}

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.
Expand Down Expand Up @@ -690,6 +742,7 @@ If you reference any of these classes in your project or module, most likely in
- [`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.
- [`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.
- [`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.
- [`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.

## Other changes

Expand Down
5 changes: 1 addition & 4 deletions en/08_Changelogs/rc/5.3.0-rc1.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ A full list of module versions included in CMS Recipe 5.3.0-rc1 is provided belo

</details>

## Release Candidate
## Release candidate

This version of Silverstripe CMS is a **release candidate** for an upcoming stable version, and should not be applied to production websites. We encourage developers to test this version in development / testing environments and [report any issues they encounter via GitHub](/contributing/issues_and_bugs/).

Expand Down Expand Up @@ -308,7 +308,6 @@ This bug has been fixed, but some additional changes were required to facilitate

The "Restore" batch action was removed from the batch actions dropdown menu in the CMS as it has not functioned correctly for a long time. There is no intention at this stage to reintroduce this feature.


<!--- Changes below this line will be automatically regenerated -->
<!-- markdownlint-disable proper-names enhanced-proper-names -->

Expand Down Expand Up @@ -1162,6 +1161,4 @@ The "Restore" batch action was removed from the batch actions dropdown menu in t
- 2023-06-16 [336dca2](https://github.com/tractorcow-farm/silverstripe-fluent/commit/336dca26d2cf0bb040cc028b005ba0c369fc21ce) Implement onAfterDuplicate (Remy Vaartjes)
- 2023-05-31 [034dd15](https://github.com/tractorcow-farm/silverstripe-fluent/commit/034dd15197ada07594436d4d337246eeda734a36) Update FluentExtension.php (mikey-harveycameron)



<!--- Changes above this line will be automatically regenerated -->

0 comments on commit 0e8d5ae

Please sign in to comment.