mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
API Strong typing for the view layer (#11351)
This commit is contained in:
parent
e1428f27a2
commit
ea93316d9c
@ -17,13 +17,6 @@ use BadMethodCallException;
|
||||
*/
|
||||
class RSSFeed_Entry extends ViewableData
|
||||
{
|
||||
/**
|
||||
* The object that represents the item, it contains all the data.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $failover;
|
||||
|
||||
/**
|
||||
* Name of the title field of feed entries
|
||||
*
|
||||
|
@ -236,7 +236,7 @@ class TaskRunner extends Controller implements PermissionProvider
|
||||
}
|
||||
return count($this->getTaskList()) > 0;
|
||||
}
|
||||
|
||||
|
||||
public function providePermissions(): array
|
||||
{
|
||||
return [
|
||||
|
@ -514,7 +514,7 @@ class CompositeField extends FormField
|
||||
return false;
|
||||
}
|
||||
|
||||
public function debug()
|
||||
public function debug(): string
|
||||
{
|
||||
$class = static::class;
|
||||
$result = "$class ($this->name) <ul>";
|
||||
|
@ -521,7 +521,7 @@ class Form extends ViewableData implements HasRequestHandler
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function castingHelper($field, bool $useFallback = true)
|
||||
public function castingHelper(string $field, bool $useFallback = true): ?string
|
||||
{
|
||||
// Override casting for field message
|
||||
if (strcasecmp($field ?? '', 'Message') === 0 && ($helper = $this->getMessageCastingHelper())) {
|
||||
@ -1547,10 +1547,8 @@ class Form extends ViewableData implements HasRequestHandler
|
||||
*
|
||||
* This is returned when you access a form as $FormObject rather
|
||||
* than <% with FormObject %>
|
||||
*
|
||||
* @return DBHTMLText
|
||||
*/
|
||||
public function forTemplate()
|
||||
public function forTemplate(): string
|
||||
{
|
||||
if (!$this->canBeCached()) {
|
||||
HTTPCacheControlMiddleware::singleton()->disableCache();
|
||||
@ -1750,7 +1748,7 @@ class Form extends ViewableData implements HasRequestHandler
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function debug()
|
||||
public function debug(): string
|
||||
{
|
||||
$class = static::class;
|
||||
$result = "<h3>$class</h3><ul>";
|
||||
|
@ -790,7 +790,7 @@ class FormField extends RequestHandler
|
||||
return $form->getSecurityToken()->isEnabled();
|
||||
}
|
||||
|
||||
public function castingHelper($field, bool $useFallback = true)
|
||||
public function castingHelper(string $field, bool $useFallback = true): ?string
|
||||
{
|
||||
// Override casting for field message
|
||||
if (strcasecmp($field ?? '', 'Message') === 0 && ($helper = $this->getMessageCastingHelper())) {
|
||||
@ -1269,7 +1269,7 @@ class FormField extends RequestHandler
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function debug()
|
||||
public function debug(): string
|
||||
{
|
||||
$strValue = is_string($this->value) ? $this->value : print_r($this->value, true);
|
||||
|
||||
@ -1286,10 +1286,8 @@ class FormField extends RequestHandler
|
||||
/**
|
||||
* This function is used by the template processor. If you refer to a field as a $ variable, it
|
||||
* will return the $Field value.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function forTemplate()
|
||||
public function forTemplate(): string
|
||||
{
|
||||
return $this->Field();
|
||||
}
|
||||
|
@ -504,7 +504,7 @@ class FormRequestHandler extends RequestHandler
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function forTemplate()
|
||||
public function forTemplate(): string
|
||||
{
|
||||
return $this->form->forTemplate();
|
||||
}
|
||||
|
@ -968,7 +968,7 @@ class GridFieldDetailForm_ItemRequest extends RequestHandler
|
||||
* Get Pjax response negotiator so form submission mirrors other form submission in the CMS.
|
||||
* See LeftAndMain::getResponseNegotiator()
|
||||
*/
|
||||
private function getResponseNegotiator(DBHTMLText $renderedForm): PjaxResponseNegotiator
|
||||
private function getResponseNegotiator(string $renderedForm): PjaxResponseNegotiator
|
||||
{
|
||||
return new PjaxResponseNegotiator([
|
||||
'default' => function () use ($renderedForm) {
|
||||
|
@ -166,7 +166,7 @@ class NullableField extends FormField
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function debug()
|
||||
public function debug(): string
|
||||
{
|
||||
$result = sprintf(
|
||||
'%s (%s: %s : <span style="color: red">%s</span>) = ',
|
||||
|
@ -56,7 +56,7 @@ class ReadonlyField extends FormField
|
||||
return 'readonly';
|
||||
}
|
||||
|
||||
public function castingHelper($field, bool $useFallback = true)
|
||||
public function castingHelper(string $field, bool $useFallback = true): ?string
|
||||
{
|
||||
// Get dynamic cast for 'Value' field
|
||||
if (strcasecmp($field ?? '', 'Value') === 0) {
|
||||
|
@ -58,7 +58,7 @@ class RequiredFields extends Validator
|
||||
* Debug helper
|
||||
* @return string
|
||||
*/
|
||||
public function debug()
|
||||
public function debug(): string
|
||||
{
|
||||
if (!is_array($this->required)) {
|
||||
return false;
|
||||
|
@ -110,10 +110,8 @@ class ArrayList extends ViewableData implements SS_List, Filterable, Sortable, L
|
||||
|
||||
/**
|
||||
* Returns true if this list has items
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function exists()
|
||||
public function exists(): bool
|
||||
{
|
||||
return !empty($this->items);
|
||||
}
|
||||
@ -159,7 +157,7 @@ class ArrayList extends ViewableData implements SS_List, Filterable, Sortable, L
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function debug()
|
||||
public function debug(): string
|
||||
{
|
||||
$val = "<h2>" . static::class . "</h2><ul>";
|
||||
foreach ($this->toNestedArray() as $item) {
|
||||
|
@ -868,7 +868,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function debug()
|
||||
public function debug(): string
|
||||
{
|
||||
$val = "<h2>" . static::class . "</h2><ul>";
|
||||
foreach ($this->toNestedArray() as $item) {
|
||||
@ -1702,10 +1702,8 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
|
||||
|
||||
/**
|
||||
* Returns true if this DataList has items
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function exists()
|
||||
public function exists(): bool
|
||||
{
|
||||
return $this->dataQuery->exists();
|
||||
}
|
||||
|
@ -816,10 +816,8 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
* Returns true if this object "exists", i.e., has a sensible value.
|
||||
* The default behaviour for a DataObject is to return true if
|
||||
* the object exists in the database, you can override this in subclasses.
|
||||
*
|
||||
* @return boolean true if this object exists
|
||||
*/
|
||||
public function exists()
|
||||
public function exists(): bool
|
||||
{
|
||||
return $this->isInDB();
|
||||
}
|
||||
@ -2686,7 +2684,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
return $untabbedFields;
|
||||
}
|
||||
|
||||
public function getViewerTemplates($suffix = '')
|
||||
public function getViewerTemplates(string $suffix = ''): array
|
||||
{
|
||||
return SSViewer::get_templates_by_class(static::class, $suffix, $this->baseClass());
|
||||
}
|
||||
@ -2713,11 +2711,8 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
/**
|
||||
* Gets the value of a field.
|
||||
* Called by {@link __get()} and any getFieldName() methods you might create.
|
||||
*
|
||||
* @param string $field The name of the field
|
||||
* @return mixed The field value
|
||||
*/
|
||||
public function getField($field)
|
||||
public function getField(string $field): mixed
|
||||
{
|
||||
// If we already have a value in $this->record, then we should just return that
|
||||
if (isset($this->record[$field])) {
|
||||
@ -2928,12 +2923,8 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
/**
|
||||
* Set the value of the field
|
||||
* Called by {@link __set()} and any setFieldName() methods you might create.
|
||||
*
|
||||
* @param string $fieldName Name of the field
|
||||
* @param mixed $val New field value
|
||||
* @return $this
|
||||
*/
|
||||
public function setField($fieldName, $val)
|
||||
public function setField(string $fieldName, mixed $value): static
|
||||
{
|
||||
$this->objCacheClear();
|
||||
//if it's a has_one component, destroy the cache
|
||||
@ -2952,42 +2943,42 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
if ($schema->unaryComponent(static::class, $fieldName)) {
|
||||
unset($this->components[$fieldName]);
|
||||
// Assign component directly
|
||||
if (is_null($val) || $val instanceof DataObject) {
|
||||
return $this->setComponent($fieldName, $val);
|
||||
if (is_null($value) || $value instanceof DataObject) {
|
||||
return $this->setComponent($fieldName, $value);
|
||||
}
|
||||
// Assign by ID instead of object
|
||||
if (is_numeric($val)) {
|
||||
if (is_numeric($value)) {
|
||||
$fieldName .= 'ID';
|
||||
}
|
||||
}
|
||||
|
||||
// Situation 1: Passing an DBField
|
||||
if ($val instanceof DBField) {
|
||||
$val->setName($fieldName);
|
||||
$val->saveInto($this);
|
||||
if ($value instanceof DBField) {
|
||||
$value->setName($fieldName);
|
||||
$value->saveInto($this);
|
||||
|
||||
// Situation 1a: Composite fields should remain bound in case they are
|
||||
// later referenced to update the parent dataobject
|
||||
if ($val instanceof DBComposite) {
|
||||
$val->bindTo($this);
|
||||
$this->setFieldValue($fieldName, $val);
|
||||
if ($value instanceof DBComposite) {
|
||||
$value->bindTo($this);
|
||||
$this->setFieldValue($fieldName, $value);
|
||||
}
|
||||
// Situation 2: Passing a literal or non-DBField object
|
||||
} else {
|
||||
$this->setFieldValue($fieldName, $val);
|
||||
$this->setFieldValue($fieldName, $value);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function setFieldValue(string $fieldName, mixed $val): void
|
||||
private function setFieldValue(string $fieldName, mixed $value): void
|
||||
{
|
||||
$schema = static::getSchema();
|
||||
// If this is a proper database field, we shouldn't be getting non-DBField objects
|
||||
if (is_object($val) && !($val instanceof DBField) && $schema->fieldSpec(static::class, $fieldName)) {
|
||||
if (is_object($value) && !($value instanceof DBField) && $schema->fieldSpec(static::class, $fieldName)) {
|
||||
throw new InvalidArgumentException('DataObject::setFieldValue: passed an object that is not a DBField');
|
||||
}
|
||||
|
||||
if (!empty($val) && !is_scalar($val)) {
|
||||
if (!empty($value) && !is_scalar($value)) {
|
||||
$dbField = $this->dbObject($fieldName);
|
||||
if ($dbField && $dbField->scalarValueOnly()) {
|
||||
throw new InvalidArgumentException(
|
||||
@ -3000,12 +2991,12 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
}
|
||||
|
||||
// if a field is not existing or has strictly changed
|
||||
if (!array_key_exists($fieldName, $this->original ?? []) || $this->original[$fieldName] !== $val) {
|
||||
if (!array_key_exists($fieldName, $this->original ?? []) || $this->original[$fieldName] !== $value) {
|
||||
// At the very least, the type has changed
|
||||
$this->changed[$fieldName] = DataObject::CHANGE_STRICT;
|
||||
|
||||
if ((!array_key_exists($fieldName, $this->original ?? []) && $val)
|
||||
|| (array_key_exists($fieldName, $this->original ?? []) && $this->original[$fieldName] != $val)
|
||||
if ((!array_key_exists($fieldName, $this->original ?? []) && $value)
|
||||
|| (array_key_exists($fieldName, $this->original ?? []) && $this->original[$fieldName] != $value)
|
||||
) {
|
||||
// Value has changed as well, not just the type
|
||||
$this->changed[$fieldName] = DataObject::CHANGE_VALUE;
|
||||
@ -3016,7 +3007,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
}
|
||||
|
||||
// Value is saved regardless, since the change detection relates to the last write
|
||||
$this->record[$fieldName] = $val;
|
||||
$this->record[$fieldName] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -3047,7 +3038,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function castingHelper($field, bool $useFallback = true)
|
||||
public function castingHelper(string $field, bool $useFallback = true): ?string
|
||||
{
|
||||
$fieldSpec = static::getSchema()->fieldSpec(static::class, $field);
|
||||
if ($fieldSpec) {
|
||||
@ -3072,19 +3063,16 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
* Returns true if the given field exists in a database column on any of
|
||||
* the objects tables and optionally look up a dynamic getter with
|
||||
* get<fieldName>().
|
||||
*
|
||||
* @param string $field Name of the field
|
||||
* @return boolean True if the given field exists
|
||||
*/
|
||||
public function hasField($field)
|
||||
public function hasField(string $fieldName): bool
|
||||
{
|
||||
$schema = static::getSchema();
|
||||
return (
|
||||
array_key_exists($field, $this->record ?? [])
|
||||
|| array_key_exists($field, $this->components ?? [])
|
||||
|| $schema->fieldSpec(static::class, $field)
|
||||
|| $schema->unaryComponent(static::class, $field)
|
||||
|| $this->hasMethod("get{$field}")
|
||||
array_key_exists($fieldName, $this->record ?? [])
|
||||
|| array_key_exists($fieldName, $this->components ?? [])
|
||||
|| $schema->fieldSpec(static::class, $fieldName)
|
||||
|| $schema->unaryComponent(static::class, $fieldName)
|
||||
|| $this->hasMethod("get{$fieldName}")
|
||||
);
|
||||
}
|
||||
|
||||
@ -3232,7 +3220,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
*
|
||||
* @return string HTML data representing this object
|
||||
*/
|
||||
public function debug()
|
||||
public function debug(): string
|
||||
{
|
||||
$class = static::class;
|
||||
$val = "<h3>Database record: {$class}</h3>\n<ul>\n";
|
||||
@ -4405,13 +4393,8 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
||||
/**
|
||||
* Returns true if the given method/parameter has a value
|
||||
* (Uses the DBField::hasValue if the parameter is a database field)
|
||||
*
|
||||
* @param string $field The field name
|
||||
* @param array $arguments
|
||||
* @param bool $cache
|
||||
* @return boolean
|
||||
*/
|
||||
public function hasValue($field, $arguments = null, $cache = true)
|
||||
public function hasValue(string $field, array $arguments = [], bool $cache = true): bool
|
||||
{
|
||||
// has_one fields should not use dbObject to check if a value is given
|
||||
$hasOne = static::getSchema()->hasOneComponent(static::class, $field);
|
||||
|
@ -36,7 +36,7 @@ interface DataObjectInterface
|
||||
* @param string $fieldName
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($fieldName);
|
||||
public function __get(string $property): mixed;
|
||||
|
||||
/**
|
||||
* Save content from a form into a field on this data object.
|
||||
|
@ -341,7 +341,7 @@ class EagerLoadedList extends ViewableData implements Relation, SS_List, Filtera
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function debug()
|
||||
public function debug(): string
|
||||
{
|
||||
// Same implementation as DataList::debug()
|
||||
$val = '<h2>' . static::class . '</h2><ul>';
|
||||
|
@ -15,7 +15,7 @@ use SilverStripe\ORM\DB;
|
||||
class DBBigInt extends DBInt
|
||||
{
|
||||
|
||||
public function requireField()
|
||||
public function requireField(): void
|
||||
{
|
||||
$parts = [
|
||||
'datatype' => 'bigint',
|
||||
|
@ -4,21 +4,23 @@ namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use SilverStripe\Forms\CheckboxField;
|
||||
use SilverStripe\Forms\DropdownField;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\View\ViewableData;
|
||||
|
||||
/**
|
||||
* Represents a boolean field.
|
||||
*/
|
||||
class DBBoolean extends DBField
|
||||
{
|
||||
public function __construct($name = null, $defaultVal = 0)
|
||||
public function __construct(?string $name = null, bool|int $defaultVal = 0)
|
||||
{
|
||||
$this->defaultVal = ($defaultVal) ? 1 : 0;
|
||||
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
public function requireField()
|
||||
public function requireField(): void
|
||||
{
|
||||
$parts = [
|
||||
'datatype' => 'tinyint',
|
||||
@ -32,17 +34,17 @@ class DBBoolean extends DBField
|
||||
DB::require_field($this->tableName, $this->name, $values);
|
||||
}
|
||||
|
||||
public function Nice()
|
||||
public function Nice(): string
|
||||
{
|
||||
return ($this->value) ? _t(__CLASS__ . '.YESANSWER', 'Yes') : _t(__CLASS__ . '.NOANSWER', 'No');
|
||||
}
|
||||
|
||||
public function NiceAsBoolean()
|
||||
public function NiceAsBoolean(): string
|
||||
{
|
||||
return ($this->value) ? 'true' : 'false';
|
||||
}
|
||||
|
||||
public function saveInto($dataObject)
|
||||
public function saveInto(ViewableData $dataObject): void
|
||||
{
|
||||
$fieldName = $this->name;
|
||||
if ($fieldName) {
|
||||
@ -57,12 +59,12 @@ class DBBoolean extends DBField
|
||||
}
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null, $params = null)
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
return CheckboxField::create($this->name, $title);
|
||||
}
|
||||
|
||||
public function scaffoldSearchField($title = null)
|
||||
public function scaffoldSearchField(?string $title = null): ?FormField
|
||||
{
|
||||
$anyText = _t(__CLASS__ . '.ANY', 'Any');
|
||||
$source = [
|
||||
@ -71,16 +73,16 @@ class DBBoolean extends DBField
|
||||
0 => _t(__CLASS__ . '.NOANSWER', 'No')
|
||||
];
|
||||
|
||||
return (new DropdownField($this->name, $title, $source))
|
||||
return DropdownField::create($this->name, $title, $source)
|
||||
->setEmptyString($anyText);
|
||||
}
|
||||
|
||||
public function nullValue()
|
||||
public function nullValue(): ?int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function prepValueForDB($value)
|
||||
public function prepValueForDB(mixed $value): array|int|null
|
||||
{
|
||||
if (is_bool($value)) {
|
||||
return $value ? 1 : 0;
|
||||
|
@ -6,48 +6,40 @@ use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\View\ViewableData;
|
||||
|
||||
/**
|
||||
* Represents a classname selector, which respects obsolete clasess.
|
||||
*/
|
||||
class DBClassName extends DBEnum
|
||||
{
|
||||
|
||||
/**
|
||||
* Base classname of class to enumerate.
|
||||
* If 'DataObject' then all classes are included.
|
||||
* If empty, then the baseClass of the parent object will be used
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $baseClass = null;
|
||||
protected ?string $baseClass = null;
|
||||
|
||||
/**
|
||||
* Parent object
|
||||
*
|
||||
* @var DataObject|null
|
||||
*/
|
||||
protected $record = null;
|
||||
protected ?DataObject $record = null;
|
||||
|
||||
private static $index = true;
|
||||
private static string|bool $index = true;
|
||||
|
||||
/**
|
||||
* Create a new DBClassName field
|
||||
*
|
||||
* @param string $name Name of field
|
||||
* @param string|null $baseClass Optional base class to limit selections
|
||||
* @param array $options Optional parameters for this DBField instance
|
||||
* @param array $options Optional parameters for this DBField instance
|
||||
*/
|
||||
public function __construct($name = null, $baseClass = null, $options = [])
|
||||
public function __construct(?string $name = null, ?string $baseClass = null, array $options = [])
|
||||
{
|
||||
$this->setBaseClass($baseClass);
|
||||
parent::__construct($name, null, null, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function requireField()
|
||||
public function requireField(): void
|
||||
{
|
||||
$parts = [
|
||||
'datatype' => 'enum',
|
||||
@ -69,10 +61,8 @@ class DBClassName extends DBEnum
|
||||
|
||||
/**
|
||||
* Get the base dataclass for the list of subclasses
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBaseClass()
|
||||
public function getBaseClass(): string
|
||||
{
|
||||
// Use explicit base class
|
||||
if ($this->baseClass) {
|
||||
@ -95,25 +85,20 @@ class DBClassName extends DBEnum
|
||||
/**
|
||||
* Get the base name of the current class
|
||||
* Useful as a non-fully qualified CSS Class name in templates.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getShortName()
|
||||
public function getShortName(): string
|
||||
{
|
||||
$value = $this->getValue();
|
||||
if (empty($value) || !ClassInfo::exists($value)) {
|
||||
return null;
|
||||
return '';
|
||||
}
|
||||
return ClassInfo::shortName($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign the base class
|
||||
*
|
||||
* @param string $baseClass
|
||||
* @return $this
|
||||
*/
|
||||
public function setBaseClass($baseClass)
|
||||
public function setBaseClass(?string $baseClass): static
|
||||
{
|
||||
$this->baseClass = $baseClass;
|
||||
return $this;
|
||||
@ -121,10 +106,8 @@ class DBClassName extends DBEnum
|
||||
|
||||
/**
|
||||
* Get list of classnames that should be selectable
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getEnum()
|
||||
public function getEnum(): array
|
||||
{
|
||||
$classNames = ClassInfo::subclassesFor($this->getBaseClass());
|
||||
$dataobject = strtolower(DataObject::class);
|
||||
@ -132,7 +115,7 @@ class DBClassName extends DBEnum
|
||||
return array_values($classNames ?? []);
|
||||
}
|
||||
|
||||
public function setValue($value, $record = null, $markChanged = true)
|
||||
public function setValue(mixed $value, null|array|ViewableData $record = null, bool $markChanged = true): static
|
||||
{
|
||||
parent::setValue($value, $record, $markChanged);
|
||||
|
||||
@ -143,7 +126,7 @@ class DBClassName extends DBEnum
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDefault()
|
||||
public function getDefault(): string
|
||||
{
|
||||
// Check for assigned default
|
||||
$default = parent::getDefault();
|
||||
|
@ -7,6 +7,7 @@ use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\Queries\SQLSelect;
|
||||
use SilverStripe\View\ViewableData;
|
||||
|
||||
/**
|
||||
* Extend this class when designing a {@link DBField} that doesn't have a 1-1 mapping with a database field.
|
||||
@ -29,26 +30,21 @@ abstract class DBComposite extends DBField
|
||||
* holds an array of composite field names.
|
||||
* Don't include the fields "main name",
|
||||
* it will be prefixed in {@link requireField()}.
|
||||
*
|
||||
* @config
|
||||
* @var array
|
||||
*/
|
||||
private static $composite_db = [];
|
||||
private static array $composite_db = [];
|
||||
|
||||
/**
|
||||
* Marker as to whether this record has changed
|
||||
* Only used when deference to the parent object isn't possible
|
||||
*/
|
||||
protected $isChanged = false;
|
||||
protected bool $isChanged = false;
|
||||
|
||||
/**
|
||||
* Either the parent dataobject link, or a record of saved values for each field
|
||||
*
|
||||
* @var array|DataObject
|
||||
*/
|
||||
protected $record = [];
|
||||
protected array|ViewableData $record = [];
|
||||
|
||||
public function __set($property, $value)
|
||||
public function __set(string $property, mixed $value): void
|
||||
{
|
||||
// Prevent failover / extensions from hijacking composite field setters
|
||||
// by intentionally avoiding hasMethod()
|
||||
@ -59,7 +55,7 @@ abstract class DBComposite extends DBField
|
||||
parent::__set($property, $value);
|
||||
}
|
||||
|
||||
public function __get($property)
|
||||
public function __get(string $property): mixed
|
||||
{
|
||||
// Prevent failover / extensions from hijacking composite field getters
|
||||
// by intentionally avoiding hasMethod()
|
||||
@ -71,10 +67,8 @@ abstract class DBComposite extends DBField
|
||||
|
||||
/**
|
||||
* Write all nested fields into a manipulation
|
||||
*
|
||||
* @param array $manipulation
|
||||
*/
|
||||
public function writeToManipulation(&$manipulation)
|
||||
public function writeToManipulation(array &$manipulation): void
|
||||
{
|
||||
foreach ($this->compositeDatabaseFields() as $field => $spec) {
|
||||
// Write sub-manipulation
|
||||
@ -88,10 +82,8 @@ abstract class DBComposite extends DBField
|
||||
* and {@link $composite_db}, or any additional SQL that is required
|
||||
* to get to these columns. Will mostly just write to the {@link SQLSelect->select}
|
||||
* array.
|
||||
*
|
||||
* @param SQLSelect $query
|
||||
*/
|
||||
public function addToQuery(&$query)
|
||||
public function addToQuery(SQLSelect &$query): void
|
||||
{
|
||||
parent::addToQuery($query);
|
||||
|
||||
@ -109,12 +101,10 @@ abstract class DBComposite extends DBField
|
||||
/**
|
||||
* Return array in the format of {@link $composite_db}.
|
||||
* Used by {@link DataObject->hasOwnDatabaseField()}.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function compositeDatabaseFields()
|
||||
public function compositeDatabaseFields(): array
|
||||
{
|
||||
return $this->config()->composite_db;
|
||||
return static::config()->get('composite_db');
|
||||
}
|
||||
|
||||
|
||||
@ -122,7 +112,7 @@ abstract class DBComposite extends DBField
|
||||
* Returns true if this composite field has changed.
|
||||
* For fields bound to a DataObject, this will be cleared when the DataObject is written.
|
||||
*/
|
||||
public function isChanged()
|
||||
public function isChanged(): bool
|
||||
{
|
||||
// When unbound, use the local changed flag
|
||||
if (!$this->record instanceof DataObject) {
|
||||
@ -141,10 +131,8 @@ abstract class DBComposite extends DBField
|
||||
|
||||
/**
|
||||
* Composite field defaults to exists only if all fields have values
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function exists()
|
||||
public function exists(): bool
|
||||
{
|
||||
// By default all fields
|
||||
foreach ($this->compositeDatabaseFields() as $field => $spec) {
|
||||
@ -156,7 +144,7 @@ abstract class DBComposite extends DBField
|
||||
return true;
|
||||
}
|
||||
|
||||
public function requireField()
|
||||
public function requireField(): void
|
||||
{
|
||||
foreach ($this->compositeDatabaseFields() as $field => $spec) {
|
||||
$key = $this->getName() . $field;
|
||||
@ -171,12 +159,9 @@ abstract class DBComposite extends DBField
|
||||
*
|
||||
* {@see ViewableData::obj}
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param mixed $record Parent object to this field, which could be a DataObject, record array, or other
|
||||
* @param bool $markChanged
|
||||
* @return $this
|
||||
* @param null|array|ViewableData $record Parent object to this field, which could be a DataObject, record array, or other
|
||||
*/
|
||||
public function setValue($value, $record = null, $markChanged = true)
|
||||
public function setValue(mixed $value, null|array|ViewableData $record = null, bool $markChanged = true): static
|
||||
{
|
||||
$this->isChanged = $markChanged;
|
||||
|
||||
@ -206,16 +191,14 @@ abstract class DBComposite extends DBField
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind this field to the dataobject, and set the underlying table to that of the owner
|
||||
*
|
||||
* @param DataObject $dataObject
|
||||
* Bind this field to the model, and set the underlying table to that of the owner
|
||||
*/
|
||||
public function bindTo($dataObject)
|
||||
public function bindTo(DataObject $dataObject): void
|
||||
{
|
||||
$this->record = $dataObject;
|
||||
}
|
||||
|
||||
public function saveInto($dataObject)
|
||||
public function saveInto(ViewableData $dataObject): void
|
||||
{
|
||||
foreach ($this->compositeDatabaseFields() as $field => $spec) {
|
||||
// Save into record
|
||||
@ -230,52 +213,44 @@ abstract class DBComposite extends DBField
|
||||
|
||||
/**
|
||||
* get value of a single composite field
|
||||
*
|
||||
* @param string $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function getField($field)
|
||||
public function getField(string $fieldName): mixed
|
||||
{
|
||||
// Skip invalid fields
|
||||
$fields = $this->compositeDatabaseFields();
|
||||
if (!isset($fields[$field])) {
|
||||
if (!isset($fields[$fieldName])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Check bound object
|
||||
if ($this->record instanceof DataObject) {
|
||||
$key = $this->getName() . $field;
|
||||
$key = $this->getName() . $fieldName;
|
||||
return $this->record->getField($key);
|
||||
}
|
||||
|
||||
// Check local record
|
||||
if (isset($this->record[$field])) {
|
||||
return $this->record[$field];
|
||||
if (isset($this->record[$fieldName])) {
|
||||
return $this->record[$fieldName];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public function hasField($field)
|
||||
public function hasField(string $fieldName): bool
|
||||
{
|
||||
$fields = $this->compositeDatabaseFields();
|
||||
return isset($fields[$field]);
|
||||
return isset($fields[$fieldName]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set value of a single composite field
|
||||
*
|
||||
* @param string $field
|
||||
* @param mixed $value
|
||||
* @param bool $markChanged
|
||||
* @return $this
|
||||
*/
|
||||
public function setField($field, $value, $markChanged = true)
|
||||
public function setField(string $fieldName, mixed $value, bool $markChanged = true): static
|
||||
{
|
||||
$this->objCacheClear();
|
||||
|
||||
if (!$this->hasField($field)) {
|
||||
if (!$this->hasField($fieldName)) {
|
||||
throw new InvalidArgumentException(implode(' ', [
|
||||
"Field $field does not exist.",
|
||||
"Field $fieldName does not exist.",
|
||||
'If this was accessed via a dynamic property then call setDynamicData() instead.'
|
||||
]));
|
||||
}
|
||||
@ -287,23 +262,20 @@ abstract class DBComposite extends DBField
|
||||
|
||||
// Set bound object
|
||||
if ($this->record instanceof DataObject) {
|
||||
$key = $this->getName() . $field;
|
||||
$key = $this->getName() . $fieldName;
|
||||
$this->record->setField($key, $value);
|
||||
return $this;
|
||||
}
|
||||
|
||||
// Set local record
|
||||
$this->record[$field] = $value;
|
||||
$this->record[$fieldName] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a db object for the named field
|
||||
*
|
||||
* @param string $field Field name
|
||||
* @return DBField|null
|
||||
*/
|
||||
public function dbObject($field)
|
||||
public function dbObject(string $field): ?DBField
|
||||
{
|
||||
$fields = $this->compositeDatabaseFields();
|
||||
if (!isset($fields[$field])) {
|
||||
@ -319,7 +291,7 @@ abstract class DBComposite extends DBField
|
||||
return $fieldObject;
|
||||
}
|
||||
|
||||
public function castingHelper($field, bool $useFallback = true)
|
||||
public function castingHelper(string $field, bool $useFallback = true): ?string
|
||||
{
|
||||
$fields = $this->compositeDatabaseFields();
|
||||
if (isset($fields[$field])) {
|
||||
@ -329,7 +301,7 @@ abstract class DBComposite extends DBField
|
||||
return parent::castingHelper($field, $useFallback);
|
||||
}
|
||||
|
||||
public function getIndexSpecs()
|
||||
public function getIndexSpecs(): array
|
||||
{
|
||||
if ($type = $this->getIndexType()) {
|
||||
$columns = array_map(function ($name) {
|
||||
@ -341,9 +313,10 @@ abstract class DBComposite extends DBField
|
||||
'columns' => $columns,
|
||||
];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
public function scalarValueOnly()
|
||||
public function scalarValueOnly(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -3,6 +3,8 @@
|
||||
namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use SilverStripe\Forms\CurrencyField;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\View\ViewableData;
|
||||
|
||||
/**
|
||||
* Represents a decimal field containing a currency amount.
|
||||
@ -20,22 +22,16 @@ use SilverStripe\Forms\CurrencyField;
|
||||
class DBCurrency extends DBDecimal
|
||||
{
|
||||
/**
|
||||
* @config
|
||||
* @var string
|
||||
* The symbol that represents the currency
|
||||
*/
|
||||
private static $currency_symbol = '$';
|
||||
|
||||
public function __construct($name = null, $wholeSize = 9, $decimalSize = 2, $defaultValue = 0)
|
||||
{
|
||||
parent::__construct($name, $wholeSize, $decimalSize, $defaultValue);
|
||||
}
|
||||
private static string $currency_symbol = '$';
|
||||
|
||||
/**
|
||||
* Returns the number as a currency, eg “$1,000.00”.
|
||||
*/
|
||||
public function Nice()
|
||||
public function Nice(): string
|
||||
{
|
||||
$val = $this->config()->currency_symbol . number_format(abs($this->value ?? 0.0) ?? 0.0, 2);
|
||||
$val = static::config()->get('currency_symbol') . number_format(abs($this->value ?? 0.0) ?? 0.0, 2);
|
||||
if ($this->value < 0) {
|
||||
return "($val)";
|
||||
}
|
||||
@ -46,22 +42,22 @@ class DBCurrency extends DBDecimal
|
||||
/**
|
||||
* Returns the number as a whole-number currency, eg “$1,000”.
|
||||
*/
|
||||
public function Whole()
|
||||
public function Whole(): string
|
||||
{
|
||||
$val = $this->config()->currency_symbol . number_format(abs($this->value ?? 0.0) ?? 0.0, 0);
|
||||
$val = static::config()->get('currency_symbol') . number_format(abs($this->value ?? 0.0) ?? 0.0, 0);
|
||||
if ($this->value < 0) {
|
||||
return "($val)";
|
||||
}
|
||||
return $val;
|
||||
}
|
||||
|
||||
public function setValue($value, $record = null, $markChanged = true)
|
||||
public function setValue(mixed $value, null|array|ViewableData $record = null, bool $markChanged = true): static
|
||||
{
|
||||
$matches = null;
|
||||
if (is_numeric($value)) {
|
||||
$this->value = $value;
|
||||
} elseif (preg_match('/-?\$?[0-9,]+(.[0-9]+)?([Ee][0-9]+)?/', $value ?? '', $matches)) {
|
||||
$this->value = str_replace(['$', ',', $this->config()->currency_symbol], '', $matches[0] ?? '');
|
||||
$this->value = str_replace(['$', ',', static::config()->get('currency_symbol')], '', $matches[0] ?? '');
|
||||
} else {
|
||||
$this->value = 0;
|
||||
}
|
||||
@ -69,13 +65,7 @@ class DBCurrency extends DBDecimal
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $title
|
||||
* @param array $params
|
||||
*
|
||||
* @return CurrencyField
|
||||
*/
|
||||
public function scaffoldFormField($title = null, $params = null)
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
return CurrencyField::create($this->getName(), $title);
|
||||
}
|
||||
|
@ -6,10 +6,12 @@ use IntlDateFormatter;
|
||||
use InvalidArgumentException;
|
||||
use NumberFormatter;
|
||||
use SilverStripe\Forms\DateField;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\i18n\i18n;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\Security\Member;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\View\ViewableData;
|
||||
|
||||
/**
|
||||
* Represents a date field.
|
||||
@ -32,15 +34,15 @@ class DBDate extends DBField
|
||||
/**
|
||||
* Standard ISO format string for date in CLDR standard format
|
||||
*/
|
||||
const ISO_DATE = 'y-MM-dd';
|
||||
public const ISO_DATE = 'y-MM-dd';
|
||||
|
||||
/**
|
||||
* Fixed locale to use for ISO date formatting. This is necessary to prevent
|
||||
* locale-specific numeric localisation breaking internal date strings.
|
||||
*/
|
||||
const ISO_LOCALE = 'en_US';
|
||||
public const ISO_LOCALE = 'en_US';
|
||||
|
||||
public function setValue($value, $record = null, $markChanged = true)
|
||||
public function setValue(mixed $value, null|array|ViewableData $record = null, bool $markChanged = true): static
|
||||
{
|
||||
$value = $this->parseDate($value);
|
||||
if ($value === false) {
|
||||
@ -58,7 +60,7 @@ class DBDate extends DBField
|
||||
* @param mixed $value
|
||||
* @return string|null|false Formatted date, null if empty but valid, or false if invalid
|
||||
*/
|
||||
protected function parseDate($value)
|
||||
protected function parseDate(mixed $value): string|null|false
|
||||
{
|
||||
// Skip empty values
|
||||
if (empty($value) && !is_numeric($value)) {
|
||||
@ -89,13 +91,11 @@ class DBDate extends DBField
|
||||
|
||||
/**
|
||||
* Returns the standard localised medium date
|
||||
*
|
||||
* @return ?string
|
||||
*/
|
||||
public function Nice()
|
||||
public function Nice(): string
|
||||
{
|
||||
if (!$this->value) {
|
||||
return null;
|
||||
return '';
|
||||
}
|
||||
$formatter = $this->getFormatter();
|
||||
return $formatter->format($this->getTimestamp());
|
||||
@ -103,40 +103,32 @@ class DBDate extends DBField
|
||||
|
||||
/**
|
||||
* Returns the year from the given date
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function Year()
|
||||
public function Year(): string
|
||||
{
|
||||
return $this->Format('y');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the day of the week
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function DayOfWeek()
|
||||
public function DayOfWeek(): string
|
||||
{
|
||||
return $this->Format('cccc');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a full textual representation of a month, such as January.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function Month()
|
||||
public function Month(): string
|
||||
{
|
||||
return $this->Format('LLLL');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the short version of the month such as Jan
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function ShortMonth()
|
||||
public function ShortMonth(): string
|
||||
{
|
||||
return $this->Format('LLL');
|
||||
}
|
||||
@ -145,9 +137,8 @@ class DBDate extends DBField
|
||||
* Returns the day of the month.
|
||||
*
|
||||
* @param bool $includeOrdinal Include ordinal suffix to day, e.g. "th" or "rd"
|
||||
* @return string
|
||||
*/
|
||||
public function DayOfMonth($includeOrdinal = false)
|
||||
public function DayOfMonth(bool $includeOrdinal = false): string
|
||||
{
|
||||
$number = $this->Format('d');
|
||||
if ($includeOrdinal && $number) {
|
||||
@ -159,13 +150,11 @@ class DBDate extends DBField
|
||||
|
||||
/**
|
||||
* Returns the date in the localised short format
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function Short()
|
||||
public function Short(): string
|
||||
{
|
||||
if (!$this->value) {
|
||||
return null;
|
||||
return '';
|
||||
}
|
||||
$formatter = $this->getFormatter(IntlDateFormatter::SHORT);
|
||||
return $formatter->format($this->getTimestamp());
|
||||
@ -173,13 +162,11 @@ class DBDate extends DBField
|
||||
|
||||
/**
|
||||
* Returns the date in the localised long format
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function Long()
|
||||
public function Long(): string
|
||||
{
|
||||
if (!$this->value) {
|
||||
return null;
|
||||
return '';
|
||||
}
|
||||
$formatter = $this->getFormatter(IntlDateFormatter::LONG);
|
||||
return $formatter->format($this->getTimestamp());
|
||||
@ -187,13 +174,11 @@ class DBDate extends DBField
|
||||
|
||||
/**
|
||||
* Returns the date in the localised full format
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function Full()
|
||||
public function Full(): string
|
||||
{
|
||||
if (!$this->value) {
|
||||
return null;
|
||||
return '';
|
||||
}
|
||||
$formatter = $this->getFormatter(IntlDateFormatter::FULL);
|
||||
return $formatter->format($this->getTimestamp());
|
||||
@ -201,12 +186,8 @@ class DBDate extends DBField
|
||||
|
||||
/**
|
||||
* Get date formatter
|
||||
*
|
||||
* @param int $dateLength
|
||||
* @param int $timeLength
|
||||
* @return IntlDateFormatter
|
||||
*/
|
||||
public function getFormatter($dateLength = IntlDateFormatter::MEDIUM, $timeLength = IntlDateFormatter::NONE)
|
||||
public function getFormatter(int $dateLength = IntlDateFormatter::MEDIUM, int $timeLength = IntlDateFormatter::NONE): IntlDateFormatter
|
||||
{
|
||||
return $this->getCustomFormatter(null, null, $dateLength, $timeLength);
|
||||
}
|
||||
@ -216,16 +197,13 @@ class DBDate extends DBField
|
||||
*
|
||||
* @param string|null $locale The current locale, or null to use default
|
||||
* @param string|null $pattern Custom pattern to use for this, if required
|
||||
* @param int $dateLength
|
||||
* @param int $timeLength
|
||||
* @return IntlDateFormatter
|
||||
*/
|
||||
public function getCustomFormatter(
|
||||
$locale = null,
|
||||
$pattern = null,
|
||||
$dateLength = IntlDateFormatter::MEDIUM,
|
||||
$timeLength = IntlDateFormatter::NONE
|
||||
) {
|
||||
?string $locale = null,
|
||||
?string $pattern = null,
|
||||
int $dateLength = IntlDateFormatter::MEDIUM,
|
||||
int $timeLength = IntlDateFormatter::NONE
|
||||
): IntlDateFormatter {
|
||||
$locale = $locale ?: i18n::get_locale();
|
||||
$formatter = IntlDateFormatter::create($locale, $dateLength, $timeLength);
|
||||
if ($pattern) {
|
||||
@ -238,9 +216,8 @@ class DBDate extends DBField
|
||||
* Formatter used internally
|
||||
*
|
||||
* @internal
|
||||
* @return IntlDateFormatter
|
||||
*/
|
||||
protected function getInternalFormatter()
|
||||
protected function getInternalFormatter(): IntlDateFormatter
|
||||
{
|
||||
$formatter = $this->getCustomFormatter(DBDate::ISO_LOCALE, DBDate::ISO_DATE);
|
||||
$formatter->setLenient(false);
|
||||
@ -249,10 +226,8 @@ class DBDate extends DBField
|
||||
|
||||
/**
|
||||
* Get standard ISO date format string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getISOFormat()
|
||||
public function getISOFormat(): string
|
||||
{
|
||||
return DBDate::ISO_DATE;
|
||||
}
|
||||
@ -262,16 +237,13 @@ class DBDate extends DBField
|
||||
* for the day of the month ("1st", "2nd", "3rd" etc)
|
||||
*
|
||||
* @param string $format Format code string. See https://unicode-org.github.io/icu/userguide/format_parse/datetime
|
||||
* @param string $locale Custom locale to use (add to signature in 5.0)
|
||||
* @return ?string The date in the requested format
|
||||
* @param string|null $locale Custom locale to use
|
||||
* @return string The date in the requested format
|
||||
*/
|
||||
public function Format($format)
|
||||
public function Format(string $format, ?string $locale = null): string
|
||||
{
|
||||
// Note: soft-arg uses func_get_args() to respect semver. Add to signature in 5.0
|
||||
$locale = func_num_args() > 1 ? func_get_arg(1) : null;
|
||||
|
||||
if (!$this->value) {
|
||||
return null;
|
||||
return '';
|
||||
}
|
||||
|
||||
// Replace {o} with ordinal representation of day of the month
|
||||
@ -285,10 +257,8 @@ class DBDate extends DBField
|
||||
|
||||
/**
|
||||
* Get unix timestamp for this date
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getTimestamp()
|
||||
public function getTimestamp(): int
|
||||
{
|
||||
if ($this->value) {
|
||||
return strtotime($this->value ?? '');
|
||||
@ -299,10 +269,9 @@ class DBDate extends DBField
|
||||
/**
|
||||
* Return a date formatted as per a CMS user's settings.
|
||||
*
|
||||
* @param Member $member
|
||||
* @return boolean | string A date formatted as per user-defined settings.
|
||||
* @return string A date formatted as per user-defined settings.
|
||||
*/
|
||||
public function FormatFromSettings($member = null)
|
||||
public function FormatFromSettings(?Member $member = null): string
|
||||
{
|
||||
if (!$member) {
|
||||
$member = Security::getCurrentUser();
|
||||
@ -512,7 +481,7 @@ class DBDate extends DBField
|
||||
}
|
||||
}
|
||||
|
||||
public function requireField()
|
||||
public function requireField(): void
|
||||
{
|
||||
$parts = ['datatype' => 'date', 'arrayValue' => $this->arrayValue];
|
||||
$values = ['type' => 'date', 'parts' => $parts];
|
||||
@ -575,7 +544,7 @@ class DBDate extends DBField
|
||||
return rawurlencode($this->Format(DBDate::ISO_DATE, DBDate::ISO_LOCALE) ?? '');
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null, $params = null)
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
$field = DateField::create($this->name, $title);
|
||||
$field->setHTML5(true);
|
||||
|
@ -6,10 +6,12 @@ use Exception;
|
||||
use IntlDateFormatter;
|
||||
use InvalidArgumentException;
|
||||
use SilverStripe\Forms\DatetimeField;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\Security\Member;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\View\TemplateGlobalProvider;
|
||||
use SilverStripe\View\ViewableData;
|
||||
|
||||
/**
|
||||
* Represents a date-time field.
|
||||
@ -37,35 +39,36 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
|
||||
* Standard ISO format string for date and time in CLDR standard format,
|
||||
* with a whitespace separating date and time (common database representation, e.g. in MySQL).
|
||||
*/
|
||||
const ISO_DATETIME = 'y-MM-dd HH:mm:ss';
|
||||
public const ISO_DATETIME = 'y-MM-dd HH:mm:ss';
|
||||
|
||||
/**
|
||||
* Standard ISO format string for date and time in CLDR standard format,
|
||||
* with a "T" separator between date and time (W3C standard, e.g. for HTML5 datetime-local fields).
|
||||
*/
|
||||
const ISO_DATETIME_NORMALISED = 'y-MM-dd\'T\'HH:mm:ss';
|
||||
public const ISO_DATETIME_NORMALISED = 'y-MM-dd\'T\'HH:mm:ss';
|
||||
|
||||
/**
|
||||
* Flag idicating if this field is considered immutable
|
||||
* when this is enabled setting the value of this field will return a new field instance
|
||||
* instead updatin the old one
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $immutable = false;
|
||||
protected bool $immutable = false;
|
||||
|
||||
/**
|
||||
* @param bool $immutable
|
||||
* @return $this
|
||||
* Used to set a specific time for "now", useful for unit tests.
|
||||
*/
|
||||
public function setImmutable(bool $immutable): DBDatetime
|
||||
protected static ?DBDatetime $mock_now = null;
|
||||
|
||||
/**
|
||||
* Set whether this field is mutable (can be modified) or immutable (cannot be modified)
|
||||
*/
|
||||
public function setImmutable(bool $immutable): static
|
||||
{
|
||||
$this->immutable = $immutable;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setValue($value, $record = null, $markChanged = true)
|
||||
public function setValue(mixed $value, null|array|ViewableData $record = null, bool $markChanged = true): static
|
||||
{
|
||||
if ($this->immutable) {
|
||||
// This field is set as immutable so we have to create a new field instance
|
||||
@ -87,10 +90,8 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
|
||||
|
||||
/**
|
||||
* Returns the standard localised date
|
||||
*
|
||||
* @return string Formatted date.
|
||||
*/
|
||||
public function Date()
|
||||
public function Date(): string
|
||||
{
|
||||
$formatter = $this->getFormatter(IntlDateFormatter::MEDIUM, IntlDateFormatter::NONE);
|
||||
return $formatter->format($this->getTimestamp());
|
||||
@ -98,10 +99,8 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
|
||||
|
||||
/**
|
||||
* Returns the standard localised time
|
||||
*
|
||||
* @return string Formatted time.
|
||||
*/
|
||||
public function Time()
|
||||
public function Time(): string
|
||||
{
|
||||
$formatter = $this->getFormatter(IntlDateFormatter::NONE, IntlDateFormatter::MEDIUM);
|
||||
return $formatter->format($this->getTimestamp());
|
||||
@ -109,20 +108,16 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
|
||||
|
||||
/**
|
||||
* Returns the time in 12-hour format using the format string 'h:mm a' e.g. '1:32 pm'.
|
||||
*
|
||||
* @return string Formatted time.
|
||||
*/
|
||||
public function Time12()
|
||||
public function Time12(): string
|
||||
{
|
||||
return $this->Format('h:mm a');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the time in 24-hour format using the format string 'H:mm' e.g. '13:32'.
|
||||
*
|
||||
* @return string Formatted time.
|
||||
*/
|
||||
public function Time24()
|
||||
public function Time24(): string
|
||||
{
|
||||
return $this->Format('H:mm');
|
||||
}
|
||||
@ -130,10 +125,9 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
|
||||
/**
|
||||
* Return a date and time formatted as per a CMS user's settings.
|
||||
*
|
||||
* @param Member $member
|
||||
* @return boolean|string A time and date pair formatted as per user-defined settings.
|
||||
* @return string A time and date pair formatted as per user-defined settings.
|
||||
*/
|
||||
public function FormatFromSettings($member = null)
|
||||
public function FormatFromSettings(?Member $member = null): string
|
||||
{
|
||||
if (!$member) {
|
||||
$member = Security::getCurrentUser();
|
||||
@ -151,7 +145,7 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
|
||||
return $this->Format($dateFormat . ' ' . $timeFormat, $member->getLocale());
|
||||
}
|
||||
|
||||
public function requireField()
|
||||
public function requireField(): void
|
||||
{
|
||||
$parts = [
|
||||
'datatype' => 'datetime',
|
||||
@ -167,15 +161,13 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
|
||||
/**
|
||||
* Returns the url encoded date and time in ISO 6801 format using format
|
||||
* string 'y-MM-dd%20HH:mm:ss' e.g. '2014-02-28%2013:32:22'.
|
||||
*
|
||||
* @return string Formatted date and time.
|
||||
*/
|
||||
public function URLDatetime()
|
||||
public function URLDatetime(): string
|
||||
{
|
||||
return rawurlencode($this->Format(DBDatetime::ISO_DATETIME, DBDatetime::ISO_LOCALE) ?? '');
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null, $params = null)
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
$field = DatetimeField::create($this->name, $title);
|
||||
$dateTimeFormat = $field->getDatetimeFormat();
|
||||
@ -195,18 +187,11 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
protected static $mock_now = null;
|
||||
|
||||
/**
|
||||
* Returns either the current system date as determined
|
||||
* by date(), or a mocked date through {@link set_mock_now()}.
|
||||
*
|
||||
* @return static
|
||||
*/
|
||||
public static function now()
|
||||
public static function now(): static
|
||||
{
|
||||
$time = DBDatetime::$mock_now ? DBDatetime::$mock_now->Value : time();
|
||||
|
||||
@ -224,7 +209,7 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
|
||||
* @param DBDatetime|string $datetime Either in object format, or as a DBDatetime compatible string.
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function set_mock_now($datetime)
|
||||
public static function set_mock_now(DBDatetime|string $datetime): void
|
||||
{
|
||||
if (!$datetime instanceof DBDatetime) {
|
||||
$value = $datetime;
|
||||
@ -240,20 +225,15 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
|
||||
* Clear any mocked date, which causes
|
||||
* {@link Now()} to return the current system date.
|
||||
*/
|
||||
public static function clear_mock_now()
|
||||
public static function clear_mock_now(): void
|
||||
{
|
||||
DBDatetime::$mock_now = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a callback with specific time, original mock value is retained after callback
|
||||
*
|
||||
* @param DBDatetime|string $time
|
||||
* @param callable $callback
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function withFixedNow($time, $callback)
|
||||
public static function withFixedNow(DBDatetime|string $time, callable $callback): mixed
|
||||
{
|
||||
$original = DBDatetime::$mock_now;
|
||||
|
||||
@ -266,7 +246,7 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
|
||||
}
|
||||
}
|
||||
|
||||
public static function get_template_global_variables()
|
||||
public static function get_template_global_variables(): array
|
||||
{
|
||||
return [
|
||||
'Now' => ['method' => 'now', 'casting' => 'Datetime'],
|
||||
@ -275,13 +255,11 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
|
||||
|
||||
/**
|
||||
* Get date / time formatter for the current locale
|
||||
*
|
||||
* @param int $dateLength
|
||||
* @param int $timeLength
|
||||
* @return IntlDateFormatter
|
||||
*/
|
||||
public function getFormatter($dateLength = IntlDateFormatter::MEDIUM, $timeLength = IntlDateFormatter::SHORT)
|
||||
{
|
||||
public function getFormatter(
|
||||
int $dateLength = IntlDateFormatter::MEDIUM,
|
||||
int $timeLength = IntlDateFormatter::SHORT
|
||||
): IntlDateFormatter {
|
||||
return parent::getFormatter($dateLength, $timeLength);
|
||||
}
|
||||
|
||||
@ -291,16 +269,13 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
|
||||
*
|
||||
* @param string|null $locale The current locale, or null to use default
|
||||
* @param string|null $pattern Custom pattern to use for this, if required
|
||||
* @param int $dateLength
|
||||
* @param int $timeLength
|
||||
* @return IntlDateFormatter
|
||||
*/
|
||||
public function getCustomFormatter(
|
||||
$locale = null,
|
||||
$pattern = null,
|
||||
$dateLength = IntlDateFormatter::MEDIUM,
|
||||
$timeLength = IntlDateFormatter::MEDIUM
|
||||
) {
|
||||
?string $locale = null,
|
||||
?string $pattern = null,
|
||||
int $dateLength = IntlDateFormatter::MEDIUM,
|
||||
int $timeLength = IntlDateFormatter::MEDIUM
|
||||
): IntlDateFormatter {
|
||||
return parent::getCustomFormatter($locale, $pattern, $dateLength, $timeLength);
|
||||
}
|
||||
|
||||
@ -308,9 +283,8 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
|
||||
* Formatter used internally
|
||||
*
|
||||
* @internal
|
||||
* @return IntlDateFormatter
|
||||
*/
|
||||
protected function getInternalFormatter()
|
||||
protected function getInternalFormatter(): IntlDateFormatter
|
||||
{
|
||||
$formatter = $this->getCustomFormatter(DBDate::ISO_LOCALE, DBDatetime::ISO_DATETIME);
|
||||
$formatter->setLenient(false);
|
||||
@ -319,10 +293,8 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
|
||||
|
||||
/**
|
||||
* Get standard ISO date format string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getISOFormat()
|
||||
public function getISOFormat(): string
|
||||
{
|
||||
return DBDatetime::ISO_DATETIME;
|
||||
}
|
||||
|
@ -2,71 +2,55 @@
|
||||
|
||||
namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\Forms\NumericField;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\View\ViewableData;
|
||||
|
||||
/**
|
||||
* Represents a Decimal field.
|
||||
*/
|
||||
class DBDecimal extends DBField
|
||||
{
|
||||
|
||||
/**
|
||||
* Whole number size
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $wholeSize = 9;
|
||||
protected int $wholeSize = 9;
|
||||
|
||||
/**
|
||||
* Decimal scale
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $decimalSize = 2;
|
||||
protected int $decimalSize = 2;
|
||||
|
||||
/**
|
||||
* Default value
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $defaultValue = 0;
|
||||
protected float|int|string $defaultValue = 0;
|
||||
|
||||
/**
|
||||
* Create a new Decimal field.
|
||||
*
|
||||
* @param string $name
|
||||
* @param int $wholeSize
|
||||
* @param int $decimalSize
|
||||
* @param float|int $defaultValue
|
||||
*/
|
||||
public function __construct($name = null, $wholeSize = 9, $decimalSize = 2, $defaultValue = 0)
|
||||
public function __construct(?string $name = null, ?int $wholeSize = 9, ?int $decimalSize = 2, float|int $defaultValue = 0)
|
||||
{
|
||||
$this->wholeSize = is_int($wholeSize) ? $wholeSize : 9;
|
||||
$this->decimalSize = is_int($decimalSize) ? $decimalSize : 2;
|
||||
|
||||
$this->defaultValue = number_format((float) $defaultValue, $decimalSize ?? 0);
|
||||
$this->defaultValue = number_format((float) $defaultValue, $this->decimalSize);
|
||||
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function Nice()
|
||||
public function Nice(): string
|
||||
{
|
||||
return number_format($this->value ?? 0.0, $this->decimalSize ?? 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return int
|
||||
*/
|
||||
public function Int()
|
||||
public function Int(): int
|
||||
{
|
||||
return floor($this->value ?? 0.0);
|
||||
}
|
||||
|
||||
public function requireField()
|
||||
public function requireField(): void
|
||||
{
|
||||
$parts = [
|
||||
'datatype' => 'decimal',
|
||||
@ -83,16 +67,16 @@ class DBDecimal extends DBField
|
||||
DB::require_field($this->tableName, $this->name, $values);
|
||||
}
|
||||
|
||||
public function saveInto($dataObject)
|
||||
public function saveInto(ViewableData $model): void
|
||||
{
|
||||
$fieldName = $this->name;
|
||||
|
||||
if ($fieldName) {
|
||||
if ($this->value instanceof DBField) {
|
||||
$this->value->saveInto($dataObject);
|
||||
$this->value->saveInto($model);
|
||||
} else {
|
||||
$value = (float) preg_replace('/[^0-9.\-\+]/', '', $this->value ?? '');
|
||||
$dataObject->__set($fieldName, $value);
|
||||
$model->__set($fieldName, $value);
|
||||
}
|
||||
} else {
|
||||
throw new \UnexpectedValueException(
|
||||
@ -101,27 +85,18 @@ class DBDecimal extends DBField
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $title
|
||||
* @param array $params
|
||||
*
|
||||
* @return NumericField
|
||||
*/
|
||||
public function scaffoldFormField($title = null, $params = null)
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
return NumericField::create($this->name, $title)
|
||||
->setScale($this->decimalSize);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function nullValue()
|
||||
public function nullValue(): ?int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function prepValueForDB($value)
|
||||
public function prepValueForDB(mixed $value): array|float|int|null
|
||||
{
|
||||
if ($value === true) {
|
||||
return 1;
|
||||
|
@ -11,7 +11,7 @@ use SilverStripe\ORM\DB;
|
||||
class DBDouble extends DBFloat
|
||||
{
|
||||
|
||||
public function requireField()
|
||||
public function requireField(): void
|
||||
{
|
||||
// HACK: MSSQL does not support double so we're using float instead
|
||||
if (DB::get_conn() instanceof MySQLDatabase) {
|
||||
|
@ -4,6 +4,8 @@ namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Forms\DropdownField;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\Forms\SelectField;
|
||||
use SilverStripe\ORM\ArrayLib;
|
||||
use SilverStripe\ORM\Connect\MySQLDatabase;
|
||||
use SilverStripe\ORM\DB;
|
||||
@ -15,35 +17,28 @@ use SilverStripe\ORM\DB;
|
||||
*/
|
||||
class DBEnum extends DBString
|
||||
{
|
||||
|
||||
/**
|
||||
* List of enum values
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $enum = [];
|
||||
protected array $enum = [];
|
||||
|
||||
/**
|
||||
* Default value
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $default = null;
|
||||
protected ?string $default = null;
|
||||
|
||||
private static $default_search_filter_class = 'ExactMatchFilter';
|
||||
private static string $default_search_filter_class = 'ExactMatchFilter';
|
||||
|
||||
/**
|
||||
* Internal cache for obsolete enum values. The top level keys are the table, each of which contains
|
||||
* nested arrays with keys mapped to field names. The values of the lowest level array are the enum values
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $enum_cache = [];
|
||||
protected static array $enum_cache = [];
|
||||
|
||||
/**
|
||||
* Clear all cached enum values.
|
||||
*/
|
||||
public static function flushCache()
|
||||
public static function flushCache(): void
|
||||
{
|
||||
DBEnum::$enum_cache = [];
|
||||
}
|
||||
@ -60,15 +55,18 @@ class DBEnum extends DBString
|
||||
* "MyField" => "Enum(['Val1', 'Val2', 'Val3'], 'Val1')" // Supports array notation as well
|
||||
* </code>
|
||||
*
|
||||
* @param string $name
|
||||
* @param string|array $enum A string containing a comma separated list of options or an array of Vals.
|
||||
* @param string|int|null $default The default option, which is either NULL or one of the items in the enumeration.
|
||||
* If passing in an integer (non-string) it will default to the index of that item in the list.
|
||||
* Set to null or empty string to allow empty values
|
||||
* @param array $options Optional parameters for this DB field
|
||||
* @param array $options Optional parameters for this DB field
|
||||
*/
|
||||
public function __construct($name = null, $enum = null, $default = 0, $options = [])
|
||||
{
|
||||
public function __construct(
|
||||
?string $name = null,
|
||||
string|array|null $enum = null,
|
||||
string|int|null $default = 0,
|
||||
array $options = []
|
||||
) {
|
||||
if ($enum) {
|
||||
$this->setEnum($enum);
|
||||
$enum = $this->getEnum();
|
||||
@ -94,10 +92,7 @@ class DBEnum extends DBString
|
||||
parent::__construct($name, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function requireField()
|
||||
public function requireField(): void
|
||||
{
|
||||
$charset = Config::inst()->get(MySQLDatabase::class, 'charset');
|
||||
$collation = Config::inst()->get(MySQLDatabase::class, 'collation');
|
||||
@ -121,18 +116,15 @@ class DBEnum extends DBString
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a dropdown field suitable for editing this field.
|
||||
*
|
||||
* @param string $title
|
||||
* @param string $name
|
||||
* @param bool $hasEmpty
|
||||
* @param string $value
|
||||
* @param string $emptyString
|
||||
* @return DropdownField
|
||||
* Return a form field suitable for editing this field.
|
||||
*/
|
||||
public function formField($title = null, $name = null, $hasEmpty = false, $value = '', $emptyString = null)
|
||||
{
|
||||
|
||||
public function formField(
|
||||
?string $title = null,
|
||||
?string $name = null,
|
||||
bool $hasEmpty = false,
|
||||
?string $value = '',
|
||||
?string $emptyString = null
|
||||
): SelectField {
|
||||
if (!$title) {
|
||||
$title = $this->getName();
|
||||
}
|
||||
@ -148,16 +140,12 @@ class DBEnum extends DBString
|
||||
return $field;
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null, $params = null)
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
return $this->formField($title);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $title
|
||||
* @return DropdownField
|
||||
*/
|
||||
public function scaffoldSearchField($title = null)
|
||||
public function scaffoldSearchField(?string $title = null): ?FormField
|
||||
{
|
||||
$anyText = _t(__CLASS__ . '.ANY', 'Any');
|
||||
return $this->formField($title, null, true, '', "($anyText)");
|
||||
@ -166,12 +154,8 @@ class DBEnum extends DBString
|
||||
/**
|
||||
* Returns the values of this enum as an array, suitable for insertion into
|
||||
* a {@link DropdownField}
|
||||
*
|
||||
* @param bool $hasEmpty
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function enumValues($hasEmpty = false)
|
||||
public function enumValues(bool $hasEmpty = false): array
|
||||
{
|
||||
return ($hasEmpty)
|
||||
? array_merge(['' => ''], ArrayLib::valuekey($this->getEnum()))
|
||||
@ -180,15 +164,12 @@ class DBEnum extends DBString
|
||||
|
||||
/**
|
||||
* Get list of enum values
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getEnum()
|
||||
public function getEnum(): array
|
||||
{
|
||||
return $this->enum;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the list of enum values, including obsolete values still present in the database
|
||||
*
|
||||
@ -196,10 +177,8 @@ class DBEnum extends DBString
|
||||
* then only known enum values are returned.
|
||||
*
|
||||
* Values cached in this method can be cleared via `DBEnum::flushCache();`
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getEnumObsolete()
|
||||
public function getEnumObsolete(): array
|
||||
{
|
||||
// Without a table or field specified, we can only retrieve known enum values
|
||||
$table = $this->getTable();
|
||||
@ -232,11 +211,8 @@ class DBEnum extends DBString
|
||||
|
||||
/**
|
||||
* Set enum options
|
||||
*
|
||||
* @param string|array $enum
|
||||
* @return $this
|
||||
*/
|
||||
public function setEnum($enum)
|
||||
public function setEnum(string|array $enum): static
|
||||
{
|
||||
if (!is_array($enum)) {
|
||||
$enum = preg_split(
|
||||
@ -250,22 +226,17 @@ class DBEnum extends DBString
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default vwalue
|
||||
*
|
||||
* @return string|null
|
||||
* Get default value
|
||||
*/
|
||||
public function getDefault()
|
||||
public function getDefault(): ?string
|
||||
{
|
||||
return $this->default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default value
|
||||
*
|
||||
* @param string $default
|
||||
* @return $this
|
||||
*/
|
||||
public function setDefault($default)
|
||||
public function setDefault(?string $default): static
|
||||
{
|
||||
$this->default = $default;
|
||||
$this->setDefaultValue($default);
|
||||
|
@ -7,7 +7,6 @@ use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\Forms\TextField;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\Filters\SearchFilter;
|
||||
use SilverStripe\ORM\Queries\SQLSelect;
|
||||
use SilverStripe\View\ViewableData;
|
||||
@ -36,7 +35,7 @@ use SilverStripe\View\ViewableData;
|
||||
*
|
||||
* <code>
|
||||
* class Blob extends DBField {
|
||||
* function requireField() {
|
||||
* function requireField(): void {
|
||||
* DB::require_field($this->tableName, $this->name, "blob");
|
||||
* }
|
||||
* }
|
||||
@ -47,65 +46,47 @@ abstract class DBField extends ViewableData implements DBIndexable
|
||||
|
||||
/**
|
||||
* Raw value of this field
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
protected $value;
|
||||
protected mixed $value = null;
|
||||
|
||||
/**
|
||||
* Table this field belongs to
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $tableName;
|
||||
protected ?string $tableName = null;
|
||||
|
||||
/**
|
||||
* Name of this field
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
protected ?string $name = null;
|
||||
|
||||
/**
|
||||
* Used for generating DB schema. {@see DBSchemaManager}
|
||||
*
|
||||
* @var array
|
||||
* Despite its name, this seems to be a string
|
||||
*/
|
||||
protected $arrayValue;
|
||||
|
||||
/**
|
||||
* Optional parameters for this field
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $options = [];
|
||||
protected array $options = [];
|
||||
|
||||
/**
|
||||
* The escape type for this field when inserted into a template - either "xml" or "raw".
|
||||
*
|
||||
* @var string
|
||||
* @config
|
||||
*/
|
||||
private static $escape_type = 'raw';
|
||||
private static string $escape_type = 'raw';
|
||||
|
||||
/**
|
||||
* Subclass of {@link SearchFilter} for usage in {@link defaultSearchFilter()}.
|
||||
*
|
||||
* @var string
|
||||
* @config
|
||||
*/
|
||||
private static $default_search_filter_class = 'PartialMatchFilter';
|
||||
private static string $default_search_filter_class = 'PartialMatchFilter';
|
||||
|
||||
/**
|
||||
* The type of index to use for this field. Can either be a string (one of the DBIndexable type options) or a
|
||||
* boolean. When a boolean is given, false will not index the field, and true will use the default index type.
|
||||
*
|
||||
* @var string|bool
|
||||
* @config
|
||||
*/
|
||||
private static $index = false;
|
||||
private static string|bool $index = false;
|
||||
|
||||
private static $casting = [
|
||||
private static array $casting = [
|
||||
'ATT' => 'HTMLFragment',
|
||||
'CDATA' => 'HTMLFragment',
|
||||
'HTML' => 'HTMLFragment',
|
||||
@ -119,20 +100,18 @@ abstract class DBField extends ViewableData implements DBIndexable
|
||||
];
|
||||
|
||||
/**
|
||||
* @var $default mixed Default-value in the database.
|
||||
* Default value in the database.
|
||||
* Might be overridden on DataObject-level, but still useful for setting defaults on
|
||||
* already existing records after a db-build.
|
||||
*/
|
||||
protected $defaultVal;
|
||||
protected mixed $defaultVal = null;
|
||||
|
||||
/**
|
||||
* Provide the DBField name and an array of options, e.g. ['index' => true], or ['nullifyEmpty' => false]
|
||||
*
|
||||
* @param string $name
|
||||
* @param array $options
|
||||
* @throws InvalidArgumentException If $options was passed by not an array
|
||||
*/
|
||||
public function __construct($name = null, $options = [])
|
||||
public function __construct(?string $name = null, array $options = [])
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
@ -154,12 +133,11 @@ abstract class DBField extends ViewableData implements DBIndexable
|
||||
* @param string $spec Class specification to construct. May include both service name and additional
|
||||
* constructor arguments in the same format as DataObject.db config.
|
||||
* @param mixed $value value of field
|
||||
* @param string $name Name of field
|
||||
* @param null|string $name Name of field
|
||||
* @param mixed $args Additional arguments to pass to constructor if not using args in service $spec
|
||||
* Note: Will raise a warning if using both
|
||||
* @return static
|
||||
*/
|
||||
public static function create_field($spec, $value, $name = null, ...$args)
|
||||
public static function create_field(string $spec, mixed $value, ?string $name = null, mixed ...$args): static
|
||||
{
|
||||
// Raise warning if inconsistent with DataObject::dbObject() behaviour
|
||||
// This will cause spec args to be shifted down by the number of provided $args
|
||||
@ -182,12 +160,8 @@ abstract class DBField extends ViewableData implements DBIndexable
|
||||
* the first place you can set a name.
|
||||
*
|
||||
* If you try an alter the name a warning will be thrown.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setName($name)
|
||||
public function setName(?string $name): static
|
||||
{
|
||||
if ($this->name && $this->name !== $name) {
|
||||
user_error("DBField::setName() shouldn't be called once a DBField already has a name."
|
||||
@ -201,20 +175,16 @@ abstract class DBField extends ViewableData implements DBIndexable
|
||||
|
||||
/**
|
||||
* Returns the name of this field.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
return $this->name ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this field.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getValue()
|
||||
public function getValue(): mixed
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
@ -228,14 +198,12 @@ abstract class DBField extends ViewableData implements DBIndexable
|
||||
* and actually changing its values, it needs a {@link $markChanged}
|
||||
* parameter.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param DataObject|array $record An array or object that this field is part of
|
||||
* @param null|ViewableData|array $record An array or object that this field is part of
|
||||
* @param bool $markChanged Indicate whether this field should be marked changed.
|
||||
* Set to FALSE if you are initializing this field after construction, rather
|
||||
* than setting a new value.
|
||||
* @return $this
|
||||
*/
|
||||
public function setValue($value, $record = null, $markChanged = true)
|
||||
public function setValue(mixed $value, null|array|ViewableData $record = null, bool $markChanged = true): static
|
||||
{
|
||||
$this->value = $value;
|
||||
return $this;
|
||||
@ -243,21 +211,16 @@ abstract class DBField extends ViewableData implements DBIndexable
|
||||
|
||||
/**
|
||||
* Get default value assigned at the DB level
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getDefaultValue()
|
||||
public function getDefaultValue(): mixed
|
||||
{
|
||||
return $this->defaultVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default value to use at the DB level
|
||||
*
|
||||
* @param mixed $defaultValue
|
||||
* @return $this
|
||||
*/
|
||||
public function setDefaultValue($defaultValue)
|
||||
public function setDefaultValue(mixed $defaultValue): static
|
||||
{
|
||||
$this->defaultVal = $defaultValue;
|
||||
return $this;
|
||||
@ -265,11 +228,8 @@ abstract class DBField extends ViewableData implements DBIndexable
|
||||
|
||||
/**
|
||||
* Update the optional parameters for this field
|
||||
*
|
||||
* @param array $options Array of options
|
||||
* @return $this
|
||||
*/
|
||||
public function setOptions(array $options = [])
|
||||
public function setOptions(array $options = []): static
|
||||
{
|
||||
$this->options = $options;
|
||||
return $this;
|
||||
@ -277,15 +237,13 @@ abstract class DBField extends ViewableData implements DBIndexable
|
||||
|
||||
/**
|
||||
* Get optional parameters for this field
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions()
|
||||
public function getOptions(): array
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
public function setIndexType($type)
|
||||
public function setIndexType($type): string|bool
|
||||
{
|
||||
if (!is_bool($type)
|
||||
&& !in_array($type, [DBIndexable::TYPE_INDEX, DBIndexable::TYPE_UNIQUE, DBIndexable::TYPE_FULLTEXT])
|
||||
@ -320,10 +278,8 @@ abstract class DBField extends ViewableData implements DBIndexable
|
||||
/**
|
||||
* Determines if the field has a value which is not considered to be 'null'
|
||||
* in a database context.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function exists()
|
||||
public function exists(): bool
|
||||
{
|
||||
return (bool)$this->value;
|
||||
}
|
||||
@ -336,7 +292,7 @@ abstract class DBField extends ViewableData implements DBIndexable
|
||||
* @param mixed $value The value to check
|
||||
* @return mixed The raw value, or escaped parameterised details
|
||||
*/
|
||||
public function prepValueForDB($value)
|
||||
public function prepValueForDB(mixed $value): mixed
|
||||
{
|
||||
if ($value === null ||
|
||||
$value === "" ||
|
||||
@ -358,10 +314,8 @@ abstract class DBField extends ViewableData implements DBIndexable
|
||||
* can also be used to apply special SQL-commands
|
||||
* to the raw value (e.g. for GIS functionality).
|
||||
* {@see prepValueForDB}
|
||||
*
|
||||
* @param array $manipulation
|
||||
*/
|
||||
public function writeToManipulation(&$manipulation)
|
||||
public function writeToManipulation(array &$manipulation): void
|
||||
{
|
||||
$manipulation['fields'][$this->name] = $this->exists()
|
||||
? $this->prepValueForDB($this->value) : $this->nullValue();
|
||||
@ -375,20 +329,15 @@ abstract class DBField extends ViewableData implements DBIndexable
|
||||
* SELECT <tablename>.* which
|
||||
* gets you the default representations
|
||||
* of all columns.
|
||||
*
|
||||
* @param SQLSelect $query
|
||||
*/
|
||||
public function addToQuery(&$query)
|
||||
public function addToQuery(SQLSelect &$query)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign this DBField to a table
|
||||
*
|
||||
* @param string $tableName
|
||||
* @return $this
|
||||
*/
|
||||
public function setTable($tableName)
|
||||
public function setTable(string $tableName): static
|
||||
{
|
||||
$this->tableName = $tableName;
|
||||
return $this;
|
||||
@ -396,20 +345,16 @@ abstract class DBField extends ViewableData implements DBIndexable
|
||||
|
||||
/**
|
||||
* Get the table this field belongs to, if assigned
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getTable()
|
||||
public function getTable(): ?string
|
||||
{
|
||||
return $this->tableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine 'default' casting for this field.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function forTemplate()
|
||||
public function forTemplate(): string
|
||||
{
|
||||
// Default to XML encoding
|
||||
return $this->XML();
|
||||
@ -417,40 +362,32 @@ abstract class DBField extends ViewableData implements DBIndexable
|
||||
|
||||
/**
|
||||
* Gets the value appropriate for a HTML attribute string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function HTMLATT()
|
||||
public function HTMLATT(): string
|
||||
{
|
||||
return Convert::raw2htmlatt($this->RAW());
|
||||
}
|
||||
|
||||
/**
|
||||
* urlencode this string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function URLATT()
|
||||
public function URLATT(): string
|
||||
{
|
||||
return urlencode($this->RAW() ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* rawurlencode this string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function RAWURLATT()
|
||||
public function RAWURLATT(): string
|
||||
{
|
||||
return rawurlencode($this->RAW() ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value appropriate for a HTML attribute string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function ATT()
|
||||
public function ATT(): string
|
||||
{
|
||||
return Convert::raw2att($this->RAW());
|
||||
}
|
||||
@ -458,60 +395,48 @@ abstract class DBField extends ViewableData implements DBIndexable
|
||||
/**
|
||||
* Gets the raw value for this field.
|
||||
* Note: Skips processors implemented via forTemplate()
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function RAW()
|
||||
public function RAW(): mixed
|
||||
{
|
||||
return $this->getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets javascript string literal value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function JS()
|
||||
public function JS(): string
|
||||
{
|
||||
return Convert::raw2js($this->RAW());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return JSON encoded value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function JSON()
|
||||
public function JSON(): string
|
||||
{
|
||||
return json_encode($this->RAW());
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for {@see XML()}
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function HTML()
|
||||
public function HTML(): string
|
||||
{
|
||||
return $this->XML();
|
||||
}
|
||||
|
||||
/**
|
||||
* XML encode this value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function XML()
|
||||
public function XML(): string
|
||||
{
|
||||
return Convert::raw2xml($this->RAW());
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely escape for XML string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function CDATA()
|
||||
public function CDATA(): string
|
||||
{
|
||||
return $this->XML();
|
||||
}
|
||||
@ -519,20 +444,16 @@ abstract class DBField extends ViewableData implements DBIndexable
|
||||
/**
|
||||
* Returns the value to be set in the database to blank this field.
|
||||
* Usually it's a choice between null, 0, and ''
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function nullValue()
|
||||
public function nullValue(): mixed
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves this field to the given data object.
|
||||
*
|
||||
* @param DataObject $dataObject
|
||||
*/
|
||||
public function saveInto($dataObject)
|
||||
public function saveInto(ViewableData $model): void
|
||||
{
|
||||
$fieldName = $this->name;
|
||||
if (empty($fieldName)) {
|
||||
@ -541,9 +462,9 @@ abstract class DBField extends ViewableData implements DBIndexable
|
||||
);
|
||||
}
|
||||
if ($this->value instanceof DBField) {
|
||||
$this->value->saveInto($dataObject);
|
||||
$this->value->saveInto($model);
|
||||
} else {
|
||||
$dataObject->__set($fieldName, $this->value);
|
||||
$model->__set($fieldName, $this->value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -554,10 +475,8 @@ abstract class DBField extends ViewableData implements DBIndexable
|
||||
* Used by {@link SearchContext}, {@link ModelAdmin}, {@link DataObject::scaffoldFormFields()}
|
||||
*
|
||||
* @param string $title Optional. Localized title of the generated instance
|
||||
* @param array $params
|
||||
* @return FormField
|
||||
*/
|
||||
public function scaffoldFormField($title = null, $params = null)
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
return TextField::create($this->name, $title);
|
||||
}
|
||||
@ -569,30 +488,28 @@ abstract class DBField extends ViewableData implements DBIndexable
|
||||
* Used by {@link SearchContext}, {@link ModelAdmin}, {@link DataObject::scaffoldFormFields()}.
|
||||
*
|
||||
* @param string $title Optional. Localized title of the generated instance
|
||||
* @return FormField
|
||||
*/
|
||||
public function scaffoldSearchField($title = null)
|
||||
public function scaffoldSearchField(?string $title = null): ?FormField
|
||||
{
|
||||
return $this->scaffoldFormField($title);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name Override name of this field
|
||||
* @return SearchFilter
|
||||
*/
|
||||
public function defaultSearchFilter($name = null)
|
||||
public function defaultSearchFilter(?string $name = null): SearchFilter
|
||||
{
|
||||
$name = ($name) ? $name : $this->name;
|
||||
$filterClass = $this->config()->get('default_search_filter_class');
|
||||
$filterClass = static::config()->get('default_search_filter_class');
|
||||
return Injector::inst()->create($filterClass, $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the field to the underlying database.
|
||||
*/
|
||||
abstract public function requireField();
|
||||
abstract public function requireField(): void;
|
||||
|
||||
public function debug()
|
||||
public function debug(): string
|
||||
{
|
||||
return <<<DBG
|
||||
<ul>
|
||||
@ -603,40 +520,31 @@ abstract class DBField extends ViewableData implements DBIndexable
|
||||
DBG;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string)$this->forTemplate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getArrayValue()
|
||||
{
|
||||
return $this->arrayValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $value
|
||||
* @return $this
|
||||
*/
|
||||
public function setArrayValue($value)
|
||||
public function setArrayValue($value): static
|
||||
{
|
||||
$this->arrayValue = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get formfield schema value
|
||||
*
|
||||
* @return string|array Encoded string for use in formschema response
|
||||
* Get formfield schema value for use in formschema response
|
||||
*/
|
||||
public function getSchemaValue()
|
||||
public function getSchemaValue(): mixed
|
||||
{
|
||||
return $this->RAW();
|
||||
}
|
||||
|
||||
public function getIndexSpecs()
|
||||
public function getIndexSpecs(): ?array
|
||||
{
|
||||
$type = $this->getIndexType();
|
||||
if ($type) {
|
||||
@ -652,9 +560,8 @@ DBG;
|
||||
* Whether or not this DBField only accepts scalar values.
|
||||
*
|
||||
* Composite DBFields can override this method and return `false` so they can accept arrays of values.
|
||||
* @return boolean
|
||||
*/
|
||||
public function scalarValueOnly()
|
||||
public function scalarValueOnly(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\Forms\NumericField;
|
||||
use SilverStripe\ORM\DB;
|
||||
|
||||
@ -10,15 +11,14 @@ use SilverStripe\ORM\DB;
|
||||
*/
|
||||
class DBFloat extends DBField
|
||||
{
|
||||
|
||||
public function __construct($name = null, $defaultVal = 0)
|
||||
public function __construct(?string $name = null, float|int $defaultVal = 0)
|
||||
{
|
||||
$this->defaultVal = is_float($defaultVal) ? $defaultVal : (float) 0;
|
||||
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
public function requireField()
|
||||
public function requireField(): void
|
||||
{
|
||||
$parts = [
|
||||
'datatype' => 'float',
|
||||
@ -35,34 +35,34 @@ class DBFloat extends DBField
|
||||
*
|
||||
* @uses number_format()
|
||||
*/
|
||||
public function Nice()
|
||||
public function Nice(): string
|
||||
{
|
||||
return number_format($this->value ?? 0.0, 2);
|
||||
}
|
||||
|
||||
public function Round($precision = 3)
|
||||
public function Round($precision = 3): float
|
||||
{
|
||||
return round($this->value ?? 0.0, $precision ?? 0);
|
||||
}
|
||||
|
||||
public function NiceRound($precision = 3)
|
||||
public function NiceRound($precision = 3): string
|
||||
{
|
||||
return number_format(round($this->value ?? 0.0, $precision ?? 0), $precision ?? 0);
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null, $params = null)
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
$field = NumericField::create($this->name, $title);
|
||||
$field->setScale(null); // remove no-decimal restriction
|
||||
return $field;
|
||||
}
|
||||
|
||||
public function nullValue()
|
||||
public function nullValue(): ?int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function prepValueForDB($value)
|
||||
public function prepValueForDB(mixed $value): array|float|int|null
|
||||
{
|
||||
if ($value === true) {
|
||||
return 1;
|
||||
|
@ -6,9 +6,11 @@ use SilverStripe\Assets\File;
|
||||
use SilverStripe\Assets\Image;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Forms\FileHandleField;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\Forms\SearchableDropdownField;
|
||||
use SilverStripe\ORM\DataList;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\View\ViewableData;
|
||||
|
||||
/**
|
||||
* A special type Int field used for foreign keys in has_one relationships.
|
||||
@ -22,40 +24,26 @@ use SilverStripe\ORM\DataObject;
|
||||
*/
|
||||
class DBForeignKey extends DBInt
|
||||
{
|
||||
/**
|
||||
* @var DataObject
|
||||
*/
|
||||
protected $object;
|
||||
protected ?DataObject $object;
|
||||
|
||||
/**
|
||||
* Number of related objects to show in a scaffolded searchable dropdown field before it
|
||||
* switches to using lazyloading.
|
||||
* This will also be used as the lazy load limit
|
||||
*
|
||||
* @config
|
||||
* @var int
|
||||
*/
|
||||
private static $dropdown_field_threshold = 100;
|
||||
private static int $dropdown_field_threshold = 100;
|
||||
|
||||
private static $index = true;
|
||||
private static string|bool $index = true;
|
||||
|
||||
private static $default_search_filter_class = 'ExactMatchFilter';
|
||||
private static string $default_search_filter_class = 'ExactMatchFilter';
|
||||
|
||||
/**
|
||||
* Cache for multiple subsequent calls to scaffold form fields with the same foreign key object
|
||||
*
|
||||
* @var array
|
||||
* @deprecated 5.2.0 Will be removed without equivalent functionality to replace it
|
||||
*/
|
||||
protected static $foreignListCache = [];
|
||||
|
||||
public function __construct($name, $object = null)
|
||||
public function __construct(?string $name, ?DataObject $object = null)
|
||||
{
|
||||
$this->object = $object;
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null, $params = null)
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
if (empty($this->object)) {
|
||||
return null;
|
||||
@ -70,11 +58,11 @@ class DBForeignKey extends DBInt
|
||||
return $field;
|
||||
}
|
||||
|
||||
public function setValue($value, $record = null, $markChanged = true)
|
||||
public function setValue(mixed $value, null|array|ViewableData $record = null, bool $markChanged = true): static
|
||||
{
|
||||
if ($record instanceof DataObject) {
|
||||
$this->object = $record;
|
||||
}
|
||||
parent::setValue($value, $record, $markChanged);
|
||||
return parent::setValue($value, $record, $markChanged);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use SilverStripe\Control\HTTP;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\Forms\HTMLEditor\HTMLEditorField;
|
||||
use SilverStripe\Forms\TextField;
|
||||
use SilverStripe\View\Parsers\HTMLValue;
|
||||
@ -25,9 +26,9 @@ use SilverStripe\View\Parsers\ShortcodeParser;
|
||||
*/
|
||||
class DBHTMLText extends DBText
|
||||
{
|
||||
private static $escape_type = 'xml';
|
||||
private static string $escape_type = 'xml';
|
||||
|
||||
private static $casting = [
|
||||
private static array $casting = [
|
||||
"AbsoluteLinks" => "HTMLFragment",
|
||||
// DBString conversion / summary methods
|
||||
// Not overridden, but returns HTML instead of plain text.
|
||||
@ -37,68 +38,52 @@ class DBHTMLText extends DBText
|
||||
|
||||
/**
|
||||
* Enable shortcode parsing on this field
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $processShortcodes = false;
|
||||
protected bool $processShortcodes = false;
|
||||
|
||||
/**
|
||||
* List of html properties to whitelist
|
||||
*/
|
||||
protected array $whitelist = [];
|
||||
|
||||
/**
|
||||
* Check if shortcodes are enabled
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getProcessShortcodes()
|
||||
public function getProcessShortcodes(): bool
|
||||
{
|
||||
return $this->processShortcodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set shortcodes on or off by default
|
||||
*
|
||||
* @param bool $process
|
||||
* @return $this
|
||||
*/
|
||||
public function setProcessShortcodes($process)
|
||||
public function setProcessShortcodes(bool $process): static
|
||||
{
|
||||
$this->processShortcodes = (bool)$process;
|
||||
$this->processShortcodes = $process;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* List of html properties to whitelist
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $whitelist = [];
|
||||
|
||||
/**
|
||||
* List of html properties to whitelist
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getWhitelist()
|
||||
public function getWhitelist(): array
|
||||
{
|
||||
return $this->whitelist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set list of html properties to whitelist
|
||||
*
|
||||
* @param array $whitelist
|
||||
* @return $this
|
||||
*/
|
||||
public function setWhitelist($whitelist)
|
||||
public function setWhitelist(string|array $whitelist): static
|
||||
{
|
||||
if (!is_array($whitelist)) {
|
||||
$whitelist = preg_split('/\s*,\s*/', $whitelist ?? '');
|
||||
$whitelist = preg_split('/\s*,\s*/', $whitelist);
|
||||
}
|
||||
$this->whitelist = $whitelist;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*
|
||||
* Options accepted in addition to those provided by Text:
|
||||
*
|
||||
* - shortcodes: If true, shortcodes will be turned into the appropriate HTML.
|
||||
@ -110,10 +95,8 @@ class DBHTMLText extends DBText
|
||||
* Text nodes outside of HTML tags are filtered out by default, but may be included by adding
|
||||
* the text() directive. E.g. 'link,meta,text()' will allow only <link /> <meta /> and text at
|
||||
* the root level.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setOptions(array $options = [])
|
||||
public function setOptions(array $options = []): static
|
||||
{
|
||||
if (array_key_exists("shortcodes", $options ?? [])) {
|
||||
$this->setProcessShortcodes(!!$options["shortcodes"]);
|
||||
@ -126,7 +109,7 @@ class DBHTMLText extends DBText
|
||||
return parent::setOptions($options);
|
||||
}
|
||||
|
||||
public function RAW()
|
||||
public function RAW(): ?string
|
||||
{
|
||||
if ($this->processShortcodes) {
|
||||
return ShortcodeParser::get_active()->parse($this->value);
|
||||
@ -136,25 +119,22 @@ class DBHTMLText extends DBText
|
||||
|
||||
/**
|
||||
* Return the value of the field with relative links converted to absolute urls (with placeholders parsed).
|
||||
* @return string
|
||||
*/
|
||||
public function AbsoluteLinks()
|
||||
public function AbsoluteLinks(): string
|
||||
{
|
||||
return HTTP::absoluteURLs($this->forTemplate());
|
||||
}
|
||||
|
||||
public function forTemplate()
|
||||
public function forTemplate(): string
|
||||
{
|
||||
// Suppress XML encoding for DBHtmlText
|
||||
return $this->RAW();
|
||||
return $this->RAW() ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely escape for XML string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function CDATA()
|
||||
public function CDATA(): string
|
||||
{
|
||||
return sprintf(
|
||||
'<![CDATA[%s]]>',
|
||||
@ -162,7 +142,7 @@ class DBHTMLText extends DBText
|
||||
);
|
||||
}
|
||||
|
||||
public function prepValueForDB($value)
|
||||
public function prepValueForDB(mixed $value): array|string|null
|
||||
{
|
||||
return parent::prepValueForDB($this->whitelistContent($value));
|
||||
}
|
||||
@ -173,7 +153,7 @@ class DBHTMLText extends DBText
|
||||
* @param string $value Input html content
|
||||
* @return string Value with all non-whitelisted content stripped (if applicable)
|
||||
*/
|
||||
public function whitelistContent($value)
|
||||
public function whitelistContent(mixed $value): mixed
|
||||
{
|
||||
if ($this->whitelist) {
|
||||
$dom = HTMLValue::create($value);
|
||||
@ -199,22 +179,20 @@ class DBHTMLText extends DBText
|
||||
return $value;
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null, $params = null)
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
return HTMLEditorField::create($this->name, $title);
|
||||
}
|
||||
|
||||
public function scaffoldSearchField($title = null)
|
||||
public function scaffoldSearchField(?string $title = null): ?FormField
|
||||
{
|
||||
return new TextField($this->name, $title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get plain-text version
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function Plain()
|
||||
public function Plain(): string
|
||||
{
|
||||
// Preserve line breaks
|
||||
$text = preg_replace('/\<br(\s*)?\/?\>/i', "\n", $this->RAW() ?? '');
|
||||
@ -232,7 +210,7 @@ class DBHTMLText extends DBText
|
||||
return trim(Convert::xml2raw($text) ?? '');
|
||||
}
|
||||
|
||||
public function getSchemaValue()
|
||||
public function getSchemaValue(): ?array
|
||||
{
|
||||
// Form schema format as HTML
|
||||
$value = $this->RAW();
|
||||
@ -242,7 +220,7 @@ class DBHTMLText extends DBText
|
||||
return null;
|
||||
}
|
||||
|
||||
public function exists()
|
||||
public function exists(): bool
|
||||
{
|
||||
// Optimisation: don't process shortcode just for ->exists()
|
||||
$value = $this->getValue();
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\Forms\HTMLEditor\HTMLEditorField;
|
||||
use SilverStripe\Forms\TextField;
|
||||
use SilverStripe\View\Parsers\ShortcodeParser;
|
||||
@ -14,10 +15,9 @@ use SilverStripe\View\Parsers\ShortcodeParser;
|
||||
*/
|
||||
class DBHTMLVarchar extends DBVarchar
|
||||
{
|
||||
private static string $escape_type = 'xml';
|
||||
|
||||
private static $escape_type = 'xml';
|
||||
|
||||
private static $casting = [
|
||||
private static array $casting = [
|
||||
// DBString conversion / summary methods
|
||||
// Not overridden, but returns HTML instead of plain text.
|
||||
"LowerCase" => "HTMLFragment",
|
||||
@ -26,35 +26,27 @@ class DBHTMLVarchar extends DBVarchar
|
||||
|
||||
/**
|
||||
* Enable shortcode parsing on this field
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $processShortcodes = false;
|
||||
protected bool $processShortcodes = false;
|
||||
|
||||
/**
|
||||
* Check if shortcodes are enabled
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getProcessShortcodes()
|
||||
public function getProcessShortcodes(): bool
|
||||
{
|
||||
return $this->processShortcodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set shortcodes on or off by default
|
||||
*
|
||||
* @param bool $process
|
||||
* @return $this
|
||||
*/
|
||||
public function setProcessShortcodes($process)
|
||||
public function setProcessShortcodes(bool $process): static
|
||||
{
|
||||
$this->processShortcodes = (bool)$process;
|
||||
$this->processShortcodes = $process;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $options
|
||||
*
|
||||
* Options accepted in addition to those provided by Text:
|
||||
*
|
||||
* - shortcodes: If true, shortcodes will be turned into the appropriate HTML.
|
||||
@ -66,10 +58,8 @@ class DBHTMLVarchar extends DBVarchar
|
||||
* Text nodes outside of HTML tags are filtered out by default, but may be included by adding
|
||||
* the text() directive. E.g. 'link,meta,text()' will allow only <link /> <meta /> and text at
|
||||
* the root level.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setOptions(array $options = [])
|
||||
public function setOptions(array $options = []): static
|
||||
{
|
||||
if (array_key_exists("shortcodes", $options ?? [])) {
|
||||
$this->setProcessShortcodes(!!$options["shortcodes"]);
|
||||
@ -78,13 +68,13 @@ class DBHTMLVarchar extends DBVarchar
|
||||
return parent::setOptions($options);
|
||||
}
|
||||
|
||||
public function forTemplate()
|
||||
public function forTemplate(): string
|
||||
{
|
||||
// Suppress XML encoding for DBHtmlText
|
||||
return $this->RAW();
|
||||
return $this->RAW() ?? '';
|
||||
}
|
||||
|
||||
public function RAW()
|
||||
public function RAW(): ?string
|
||||
{
|
||||
if ($this->processShortcodes) {
|
||||
return ShortcodeParser::get_active()->parse($this->value);
|
||||
@ -94,10 +84,8 @@ class DBHTMLVarchar extends DBVarchar
|
||||
|
||||
/**
|
||||
* Safely escape for XML string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function CDATA()
|
||||
public function CDATA(): string
|
||||
{
|
||||
return sprintf(
|
||||
'<![CDATA[%s]]>',
|
||||
@ -109,10 +97,8 @@ class DBHTMLVarchar extends DBVarchar
|
||||
* Get plain-text version.
|
||||
*
|
||||
* Note: unlike DBHTMLText, this doesn't respect line breaks / paragraphs
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function Plain()
|
||||
public function Plain(): string
|
||||
{
|
||||
// Strip out HTML
|
||||
$text = strip_tags($this->RAW() ?? '');
|
||||
@ -121,17 +107,17 @@ class DBHTMLVarchar extends DBVarchar
|
||||
return trim(Convert::xml2raw($text) ?? '');
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null, $params = null)
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
return HTMLEditorField::create($this->name, $title);
|
||||
}
|
||||
|
||||
public function scaffoldSearchField($title = null)
|
||||
public function scaffoldSearchField(?string $title = null): ?FormField
|
||||
{
|
||||
return TextField::create($this->name, $title);
|
||||
}
|
||||
|
||||
public function getSchemaValue()
|
||||
public function getSchemaValue(): ?array
|
||||
{
|
||||
// Form schema format as HTML
|
||||
$value = $this->RAW();
|
||||
@ -141,7 +127,7 @@ class DBHTMLVarchar extends DBVarchar
|
||||
return null;
|
||||
}
|
||||
|
||||
public function exists()
|
||||
public function exists(): bool
|
||||
{
|
||||
// Optimisation: don't process shortcode just for ->exists()
|
||||
$value = $this->getValue();
|
||||
|
@ -2,9 +2,11 @@
|
||||
|
||||
namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\Forms\NumericField;
|
||||
use SilverStripe\ORM\ArrayList;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\SS_List;
|
||||
use SilverStripe\View\ArrayData;
|
||||
|
||||
/**
|
||||
@ -12,8 +14,7 @@ use SilverStripe\View\ArrayData;
|
||||
*/
|
||||
class DBInt extends DBField
|
||||
{
|
||||
|
||||
public function __construct($name = null, $defaultVal = 0)
|
||||
public function __construct(?string $name = null, int $defaultVal = 0)
|
||||
{
|
||||
$this->defaultVal = is_int($defaultVal) ? $defaultVal : 0;
|
||||
|
||||
@ -24,7 +25,7 @@ class DBInt extends DBField
|
||||
* Ensure int values are always returned.
|
||||
* This is for mis-configured databases that return strings.
|
||||
*/
|
||||
public function getValue()
|
||||
public function getValue(): ?int
|
||||
{
|
||||
return (int) $this->value;
|
||||
}
|
||||
@ -32,12 +33,12 @@ class DBInt extends DBField
|
||||
/**
|
||||
* Returns the number, with commas added as appropriate, eg “1,000”.
|
||||
*/
|
||||
public function Formatted()
|
||||
public function Formatted(): string
|
||||
{
|
||||
return number_format($this->value ?? 0.0);
|
||||
}
|
||||
|
||||
public function requireField()
|
||||
public function requireField(): void
|
||||
{
|
||||
$parts = [
|
||||
'datatype' => 'int',
|
||||
@ -50,7 +51,7 @@ class DBInt extends DBField
|
||||
DB::require_field($this->tableName, $this->name, $values);
|
||||
}
|
||||
|
||||
public function Times()
|
||||
public function Times(): SS_List
|
||||
{
|
||||
$output = new ArrayList();
|
||||
for ($i = 0; $i < $this->value; $i++) {
|
||||
@ -60,22 +61,22 @@ class DBInt extends DBField
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function Nice()
|
||||
public function Nice(): string
|
||||
{
|
||||
return sprintf('%d', $this->value);
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null, $params = null)
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
return NumericField::create($this->name, $title);
|
||||
}
|
||||
|
||||
public function nullValue()
|
||||
public function nullValue(): ?int
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function prepValueForDB($value)
|
||||
public function prepValueForDB(mixed $value): array|int|null
|
||||
{
|
||||
if ($value === true) {
|
||||
return 1;
|
||||
|
@ -9,8 +9,7 @@ use SilverStripe\i18n\i18n;
|
||||
*/
|
||||
class DBLocale extends DBVarchar
|
||||
{
|
||||
|
||||
public function __construct($name = null, $size = 16)
|
||||
public function __construct(?string $name = null, int $size = 16)
|
||||
{
|
||||
parent::__construct($name, $size);
|
||||
}
|
||||
@ -18,11 +17,10 @@ class DBLocale extends DBVarchar
|
||||
/**
|
||||
* See {@link getShortName()} and {@link getNativeName()}.
|
||||
*
|
||||
* @param Boolean $showNative Show a localized version of the name instead, based on the
|
||||
* @param bool $showNative Show a localized version of the name instead, based on the
|
||||
* field's locale value.
|
||||
* @return String
|
||||
*/
|
||||
public function Nice($showNative = false)
|
||||
public function Nice(bool $showNative = false): string
|
||||
{
|
||||
if ($showNative) {
|
||||
return $this->getNativeName();
|
||||
@ -30,7 +28,7 @@ class DBLocale extends DBVarchar
|
||||
return $this->getShortName();
|
||||
}
|
||||
|
||||
public function RFC1766()
|
||||
public function RFC1766(): string
|
||||
{
|
||||
return i18n::convert_rfc1766($this->value);
|
||||
}
|
||||
@ -38,18 +36,13 @@ class DBLocale extends DBVarchar
|
||||
/**
|
||||
* Resolves the locale to a common english-language
|
||||
* name through {@link i18n::get_common_locales()}.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getShortName()
|
||||
public function getShortName(): string
|
||||
{
|
||||
return i18n::getData()->languageName($this->value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLongName()
|
||||
public function getLongName(): string
|
||||
{
|
||||
return i18n::getData()->localeName($this->value);
|
||||
}
|
||||
@ -57,10 +50,8 @@ class DBLocale extends DBVarchar
|
||||
/**
|
||||
* Returns the localized name based on the field's value.
|
||||
* Example: "de_DE" returns "Deutsch".
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNativeName()
|
||||
public function getNativeName(): string
|
||||
{
|
||||
$locale = $this->value;
|
||||
return i18n::with_locale($locale, function () {
|
||||
|
@ -13,25 +13,17 @@ use SilverStripe\i18n\i18n;
|
||||
*/
|
||||
class DBMoney extends DBComposite
|
||||
{
|
||||
/**
|
||||
* @var string $locale
|
||||
*/
|
||||
protected $locale = null;
|
||||
protected ?string $locale = null;
|
||||
|
||||
/**
|
||||
* @var array<string,string>
|
||||
*/
|
||||
private static $composite_db = [
|
||||
private static array $composite_db = [
|
||||
'Currency' => 'Varchar(3)',
|
||||
'Amount' => 'Decimal(19,4)'
|
||||
];
|
||||
|
||||
/**
|
||||
* Get currency formatter
|
||||
*
|
||||
* @return NumberFormatter
|
||||
*/
|
||||
public function getFormatter()
|
||||
public function getFormatter(): NumberFormatter
|
||||
{
|
||||
$locale = $this->getLocale();
|
||||
$currency = $this->getCurrency();
|
||||
@ -43,10 +35,8 @@ class DBMoney extends DBComposite
|
||||
|
||||
/**
|
||||
* Get nicely formatted currency (based on current locale)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function Nice()
|
||||
public function Nice(): string
|
||||
{
|
||||
if (!$this->exists()) {
|
||||
return null;
|
||||
@ -66,10 +56,8 @@ class DBMoney extends DBComposite
|
||||
|
||||
/**
|
||||
* Standard '0.00 CUR' format (non-localised)
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValue()
|
||||
public function getValue(): ?string
|
||||
{
|
||||
if (!$this->exists()) {
|
||||
return null;
|
||||
@ -82,39 +70,23 @@ class DBMoney extends DBComposite
|
||||
return $amount . ' ' . $currency;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getCurrency()
|
||||
public function getCurrency(): ?string
|
||||
{
|
||||
return $this->getField('Currency');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $currency
|
||||
* @param bool $markChanged
|
||||
* @return $this
|
||||
*/
|
||||
public function setCurrency($currency, $markChanged = true)
|
||||
public function setCurrency(?string $currency, bool $markChanged = true): static
|
||||
{
|
||||
$this->setField('Currency', $currency, $markChanged);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return float
|
||||
*/
|
||||
public function getAmount()
|
||||
public function getAmount(): ?float
|
||||
{
|
||||
return $this->getField('Amount');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $amount
|
||||
* @param bool $markChanged
|
||||
* @return $this
|
||||
*/
|
||||
public function setAmount($amount, $markChanged = true)
|
||||
public function setAmount(mixed $amount, bool $markChanged = true): static
|
||||
{
|
||||
// Retain nullability to mark this field as empty
|
||||
if (isset($amount)) {
|
||||
@ -124,49 +96,35 @@ class DBMoney extends DBComposite
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return boolean
|
||||
*/
|
||||
public function exists()
|
||||
public function exists(): bool
|
||||
{
|
||||
return is_numeric($this->getAmount());
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine if this has a non-zero amount
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasAmount()
|
||||
public function hasAmount(): bool
|
||||
{
|
||||
$a = $this->getAmount();
|
||||
return (!empty($a) && is_numeric($a));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $locale
|
||||
* @return $this
|
||||
*/
|
||||
public function setLocale($locale)
|
||||
public function setLocale(string $locale): static
|
||||
{
|
||||
$this->locale = $locale;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getLocale()
|
||||
public function getLocale(): string
|
||||
{
|
||||
return $this->locale ?: i18n::get_locale();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get currency symbol
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getSymbol()
|
||||
public function getSymbol(): string
|
||||
{
|
||||
return $this->getFormatter()->getSymbol(NumberFormatter::CURRENCY_SYMBOL);
|
||||
}
|
||||
@ -178,10 +136,8 @@ class DBMoney extends DBComposite
|
||||
* Used by {@link SearchContext}, {@link ModelAdmin}, {@link DataObject::scaffoldFormFields()}
|
||||
*
|
||||
* @param string $title Optional. Localized title of the generated instance
|
||||
* @param array $params
|
||||
* @return FormField
|
||||
*/
|
||||
public function scaffoldFormField($title = null, $params = null)
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
return MoneyField::create($this->getName(), $title)
|
||||
->setLocale($this->getLocale());
|
||||
|
@ -4,6 +4,7 @@ namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Forms\CheckboxSetField;
|
||||
use SilverStripe\Forms\MultiSelectField;
|
||||
use SilverStripe\ORM\Connect\MySQLDatabase;
|
||||
use SilverStripe\ORM\DB;
|
||||
|
||||
@ -33,7 +34,7 @@ class DBMultiEnum extends DBEnum
|
||||
}
|
||||
}
|
||||
|
||||
public function requireField()
|
||||
public function requireField(): void
|
||||
{
|
||||
$charset = Config::inst()->get(MySQLDatabase::class, 'charset');
|
||||
$collation = Config::inst()->get(MySQLDatabase::class, 'collation');
|
||||
@ -54,18 +55,15 @@ class DBMultiEnum extends DBEnum
|
||||
|
||||
|
||||
/**
|
||||
* Return a {@link CheckboxSetField} suitable for editing this field
|
||||
*
|
||||
* @param string $title
|
||||
* @param string $name
|
||||
* @param bool $hasEmpty
|
||||
* @param string $value
|
||||
* @param string $emptyString
|
||||
* @return CheckboxSetField
|
||||
* Return a form field suitable for editing this field
|
||||
*/
|
||||
public function formField($title = null, $name = null, $hasEmpty = false, $value = '', $emptyString = null)
|
||||
{
|
||||
|
||||
public function formField(
|
||||
?string $title = null,
|
||||
?string $name = null,
|
||||
bool $hasEmpty = false,
|
||||
?string $value = '',
|
||||
?string $emptyString = null
|
||||
): MultiSelectField {
|
||||
if (!$title) {
|
||||
$title = $this->name;
|
||||
}
|
||||
@ -73,6 +71,6 @@ class DBMultiEnum extends DBEnum
|
||||
$name = $this->name;
|
||||
}
|
||||
|
||||
return new CheckboxSetField($name, $title, $this->enumValues($hasEmpty), $value);
|
||||
return CheckboxSetField::create($name, $title, $this->enumValues($hasEmpty), $value);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use SilverStripe\View\ViewableData;
|
||||
|
||||
/**
|
||||
* Represents a decimal field from 0-1 containing a percentage value.
|
||||
*
|
||||
@ -15,14 +17,10 @@ namespace SilverStripe\ORM\FieldType;
|
||||
*/
|
||||
class DBPercentage extends DBDecimal
|
||||
{
|
||||
|
||||
/**
|
||||
* Create a new Decimal field.
|
||||
*
|
||||
* @param string $name
|
||||
* @param int $precision
|
||||
*/
|
||||
public function __construct($name = null, $precision = 4)
|
||||
public function __construct(?string $name = null, int $precision = 4)
|
||||
{
|
||||
if (!$precision) {
|
||||
$precision = 4;
|
||||
@ -34,18 +32,18 @@ class DBPercentage extends DBDecimal
|
||||
/**
|
||||
* Returns the number, expressed as a percentage. For example, “36.30%”
|
||||
*/
|
||||
public function Nice()
|
||||
public function Nice(): string
|
||||
{
|
||||
return number_format($this->value * 100, $this->decimalSize - 2) . '%';
|
||||
}
|
||||
|
||||
public function saveInto($dataObject)
|
||||
public function saveInto(ViewableData $model): void
|
||||
{
|
||||
parent::saveInto($dataObject);
|
||||
parent::saveInto($model);
|
||||
|
||||
$fieldName = $this->name;
|
||||
if ($fieldName && $dataObject->$fieldName > 1.0) {
|
||||
$dataObject->__set($fieldName, 1.0);
|
||||
if ($fieldName && $model->$fieldName > 1.0) {
|
||||
$model->__set($fieldName, 1.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,21 +2,23 @@
|
||||
|
||||
namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\View\ViewableData;
|
||||
|
||||
/**
|
||||
* A special ForeignKey class that handles relations with arbitrary class types
|
||||
*/
|
||||
class DBPolymorphicForeignKey extends DBComposite
|
||||
{
|
||||
private static $index = true;
|
||||
private static bool $index = true;
|
||||
|
||||
private static $composite_db = [
|
||||
private static array $composite_db = [
|
||||
'ID' => 'Int',
|
||||
'Class' => "DBClassName('" . DataObject::class . "', ['index' => false])"
|
||||
];
|
||||
|
||||
public function scaffoldFormField($title = null, $params = null)
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
// Don't provide scaffolded form field generation - Scaffolding should be performed on
|
||||
// the has_many end, or set programmatically.
|
||||
@ -28,7 +30,7 @@ class DBPolymorphicForeignKey extends DBComposite
|
||||
*
|
||||
* @return string Name of a subclass of DataObject
|
||||
*/
|
||||
public function getClassValue()
|
||||
public function getClassValue(): ?string
|
||||
{
|
||||
return $this->getField('Class');
|
||||
}
|
||||
@ -37,35 +39,29 @@ class DBPolymorphicForeignKey extends DBComposite
|
||||
* Set the value of the "Class" this key points to
|
||||
*
|
||||
* @param string $value Name of a subclass of DataObject
|
||||
* @param boolean $markChanged Mark this field as changed?
|
||||
*/
|
||||
public function setClassValue($value, $markChanged = true)
|
||||
public function setClassValue(string $value, bool $markChanged = true)
|
||||
{
|
||||
$this->setField('Class', $value, $markChanged);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the "ID" this key points to
|
||||
*
|
||||
* @return integer
|
||||
*/
|
||||
public function getIDValue()
|
||||
public function getIDValue(): ?int
|
||||
{
|
||||
return $this->getField('ID');
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the "ID" this key points to
|
||||
*
|
||||
* @param integer $value
|
||||
* @param boolean $markChanged Mark this field as changed?
|
||||
*/
|
||||
public function setIDValue($value, $markChanged = true)
|
||||
public function setIDValue(int $value, bool $markChanged = true)
|
||||
{
|
||||
$this->setField('ID', $value, $markChanged);
|
||||
}
|
||||
|
||||
public function setValue($value, $record = null, $markChanged = true)
|
||||
public function setValue(mixed $value, null|array|ViewableData $record = null, bool $markChanged = true): static
|
||||
{
|
||||
// Map dataobject value to array
|
||||
if ($value instanceof DataObject) {
|
||||
@ -75,10 +71,10 @@ class DBPolymorphicForeignKey extends DBComposite
|
||||
];
|
||||
}
|
||||
|
||||
parent::setValue($value, $record, $markChanged);
|
||||
return parent::setValue($value, $record, $markChanged);
|
||||
}
|
||||
|
||||
public function getValue()
|
||||
public function getValue(): ?DataObject
|
||||
{
|
||||
$id = $this->getIDValue();
|
||||
$class = $this->getClassValue();
|
||||
|
@ -2,64 +2,59 @@
|
||||
|
||||
namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\View\ViewableData;
|
||||
|
||||
/**
|
||||
* A special type Int field used for primary keys.
|
||||
*/
|
||||
class DBPrimaryKey extends DBInt
|
||||
{
|
||||
/**
|
||||
* @var DataObject
|
||||
*/
|
||||
protected $object;
|
||||
protected ?DataObject $object;
|
||||
|
||||
private static $default_search_filter_class = 'ExactMatchFilter';
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $autoIncrement = true;
|
||||
|
||||
public function setAutoIncrement($autoIncrement)
|
||||
{
|
||||
$this->autoIncrement = $autoIncrement;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAutoIncrement()
|
||||
{
|
||||
return $this->autoIncrement;
|
||||
}
|
||||
|
||||
public function requireField()
|
||||
{
|
||||
$spec = DB::get_schema()->IdColumn(false, $this->getAutoIncrement());
|
||||
DB::require_field($this->getTable(), $this->getName(), $spec);
|
||||
}
|
||||
protected bool $autoIncrement = true;
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @param DataObject $object The object that this is primary key for (should have a relation with $name)
|
||||
*/
|
||||
public function __construct($name, $object = null)
|
||||
public function __construct(?string $name, ?DataObject $object = null)
|
||||
{
|
||||
$this->object = $object;
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null, $params = null)
|
||||
public function setAutoIncrement(bool $autoIncrement): static
|
||||
{
|
||||
$this->autoIncrement = $autoIncrement;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getAutoIncrement(): bool
|
||||
{
|
||||
return $this->autoIncrement;
|
||||
}
|
||||
|
||||
public function requireField(): void
|
||||
{
|
||||
$spec = DB::get_schema()->IdColumn(false, $this->getAutoIncrement());
|
||||
DB::require_field($this->getTable(), $this->getName(), $spec);
|
||||
}
|
||||
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public function scaffoldSearchField($title = null)
|
||||
public function scaffoldSearchField(?string $title = null): ?FormField
|
||||
{
|
||||
parent::scaffoldFormField($title);
|
||||
return parent::scaffoldFormField($title);
|
||||
}
|
||||
|
||||
public function setValue($value, $record = null, $markChanged = true)
|
||||
public function setValue(mixed $value, null|array|ViewableData $record = null, bool $markChanged = true): static
|
||||
{
|
||||
parent::setValue($value, $record, $markChanged);
|
||||
|
||||
|
@ -7,10 +7,7 @@ namespace SilverStripe\ORM\FieldType;
|
||||
*/
|
||||
abstract class DBString extends DBField
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $casting = [
|
||||
private static array $casting = [
|
||||
'LimitCharacters' => 'Text',
|
||||
'LimitCharactersToClosestWord' => 'Text',
|
||||
'LimitWordCount' => 'Text',
|
||||
@ -33,16 +30,14 @@ abstract class DBString extends DBField
|
||||
/**
|
||||
* Update the optional parameters for this field.
|
||||
*
|
||||
* @param array $options Array of options
|
||||
* The options allowed are:
|
||||
* <ul><li>"nullifyEmpty"
|
||||
* This is a boolean flag.
|
||||
* True (the default) means that empty strings are automatically converted to nulls to be stored in
|
||||
* the database. Set it to false to ensure that nulls and empty strings are kept intact in the database.
|
||||
* </li></ul>
|
||||
* @return $this
|
||||
*/
|
||||
public function setOptions(array $options = [])
|
||||
public function setOptions(array $options = []): static
|
||||
{
|
||||
parent::setOptions($options);
|
||||
|
||||
@ -63,9 +58,9 @@ abstract class DBString extends DBField
|
||||
* @param $value boolean True if empty strings are to be converted to null
|
||||
* @return $this
|
||||
*/
|
||||
public function setNullifyEmpty($value)
|
||||
public function setNullifyEmpty(bool $value): static
|
||||
{
|
||||
$this->options['nullifyEmpty'] = (bool) $value;
|
||||
$this->options['nullifyEmpty'] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -75,23 +70,19 @@ abstract class DBString extends DBField
|
||||
*
|
||||
* @return boolean True if empty strings are to be converted to null
|
||||
*/
|
||||
public function getNullifyEmpty()
|
||||
public function getNullifyEmpty(): bool
|
||||
{
|
||||
return !empty($this->options['nullifyEmpty']);
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPdoc)
|
||||
* @see DBField::exists()
|
||||
*/
|
||||
public function exists()
|
||||
public function exists(): bool
|
||||
{
|
||||
$value = $this->RAW();
|
||||
// All truthy values and non-empty strings exist ('0' but not (int)0)
|
||||
return $value || (is_string($value) && strlen($value ?? ''));
|
||||
}
|
||||
|
||||
public function prepValueForDB($value)
|
||||
public function prepValueForDB(mixed $value): array|string|null
|
||||
{
|
||||
// Cast non-empty value
|
||||
if (is_scalar($value) && strlen($value ?? '')) {
|
||||
@ -105,10 +96,7 @@ abstract class DBString extends DBField
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function forTemplate()
|
||||
public function forTemplate(): string
|
||||
{
|
||||
return nl2br(parent::forTemplate() ?? '');
|
||||
}
|
||||
@ -120,9 +108,8 @@ abstract class DBString extends DBField
|
||||
*
|
||||
* @param int $limit Number of characters to limit by
|
||||
* @param string|false $add Ellipsis to add to the end of truncated string
|
||||
* @return string
|
||||
*/
|
||||
public function LimitCharacters($limit = 20, $add = false)
|
||||
public function LimitCharacters(int $limit = 20, string|false $add = false): string
|
||||
{
|
||||
$value = $this->Plain();
|
||||
if (mb_strlen($value ?? '') <= $limit) {
|
||||
@ -140,7 +127,7 @@ abstract class DBString extends DBField
|
||||
* @param string|false $add Ellipsis to add to the end of truncated string
|
||||
* @return string Plain text value with limited characters
|
||||
*/
|
||||
public function LimitCharactersToClosestWord($limit = 20, $add = false)
|
||||
public function LimitCharactersToClosestWord(int $limit = 20, string|false $add = false): string
|
||||
{
|
||||
// Safely convert to plain text
|
||||
$value = $this->Plain();
|
||||
@ -169,11 +156,9 @@ abstract class DBString extends DBField
|
||||
* Limit this field's content by a number of words.
|
||||
*
|
||||
* @param int $numWords Number of words to limit by.
|
||||
* @param false $add Ellipsis to add to the end of truncated string.
|
||||
*
|
||||
* @return string
|
||||
* @param string|false $add Ellipsis to add to the end of truncated string.
|
||||
*/
|
||||
public function LimitWordCount($numWords = 26, $add = false)
|
||||
public function LimitWordCount(int $numWords = 26, string|false $add = false): string
|
||||
{
|
||||
$value = $this->Plain();
|
||||
$words = explode(' ', $value ?? '');
|
||||
@ -191,7 +176,7 @@ abstract class DBString extends DBField
|
||||
*
|
||||
* @return string Text with lowercase (HTML for some subclasses)
|
||||
*/
|
||||
public function LowerCase()
|
||||
public function LowerCase(): string
|
||||
{
|
||||
return mb_strtolower($this->RAW() ?? '');
|
||||
}
|
||||
@ -201,28 +186,23 @@ abstract class DBString extends DBField
|
||||
*
|
||||
* @return string Text with uppercase (HTML for some subclasses)
|
||||
*/
|
||||
public function UpperCase()
|
||||
public function UpperCase(): string
|
||||
{
|
||||
return mb_strtoupper($this->RAW() ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Plain text version of this string
|
||||
*
|
||||
* @return string Plain text
|
||||
*/
|
||||
public function Plain()
|
||||
public function Plain(): string
|
||||
{
|
||||
return trim($this->RAW() ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Swap add for defaultEllipsis if need be
|
||||
* @param string $string
|
||||
* @param false|string $add
|
||||
* @return string
|
||||
*/
|
||||
private function addEllipsis(string $string, $add): string
|
||||
private function addEllipsis(string $string, string|false $add): string
|
||||
{
|
||||
if ($add === false) {
|
||||
$add = $this->defaultEllipsis();
|
||||
@ -233,7 +213,6 @@ abstract class DBString extends DBField
|
||||
|
||||
/**
|
||||
* Get the default string to indicate that a string was cut off.
|
||||
* @return string
|
||||
*/
|
||||
public function defaultEllipsis(): string
|
||||
{
|
||||
|
@ -5,6 +5,7 @@ namespace SilverStripe\ORM\FieldType;
|
||||
use InvalidArgumentException;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\Forms\NullableField;
|
||||
use SilverStripe\Forms\TextareaField;
|
||||
use SilverStripe\Forms\TextField;
|
||||
@ -27,8 +28,7 @@ use SilverStripe\ORM\DB;
|
||||
*/
|
||||
class DBText extends DBString
|
||||
{
|
||||
|
||||
private static $casting = [
|
||||
private static array $casting = [
|
||||
'BigSummary' => 'Text',
|
||||
'ContextSummary' => 'HTMLFragment', // Always returns HTML as it contains formatting and highlighting
|
||||
'FirstParagraph' => 'Text',
|
||||
@ -42,11 +42,7 @@ class DBText extends DBString
|
||||
*/
|
||||
private static array $summary_sentence_separators = ['.', '?', '!'];
|
||||
|
||||
/**
|
||||
* (non-PHPdoc)
|
||||
* @see DBField::requireField()
|
||||
*/
|
||||
public function requireField()
|
||||
public function requireField(): void
|
||||
{
|
||||
$charset = Config::inst()->get(MySQLDatabase::class, 'charset');
|
||||
$collation = Config::inst()->get(MySQLDatabase::class, 'collation');
|
||||
@ -71,9 +67,8 @@ class DBText extends DBString
|
||||
* Limit sentences, can be controlled by passing an integer.
|
||||
*
|
||||
* @param int $maxSentences The amount of sentences you want.
|
||||
* @return string
|
||||
*/
|
||||
public function LimitSentences($maxSentences = 2)
|
||||
public function LimitSentences(int $maxSentences = 2): string
|
||||
{
|
||||
if (!is_numeric($maxSentences)) {
|
||||
throw new InvalidArgumentException("Text::LimitSentence() expects one numeric argument");
|
||||
@ -107,22 +102,16 @@ class DBText extends DBString
|
||||
|
||||
/**
|
||||
* Return the first string that finishes with a period (.) in this text.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function FirstSentence()
|
||||
public function FirstSentence(): string
|
||||
{
|
||||
return $this->LimitSentences(1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a basic summary, up to a maximum number of words
|
||||
*
|
||||
* @param int $maxWords
|
||||
* @param string|false $add
|
||||
* @return string
|
||||
*/
|
||||
public function Summary($maxWords = 50, $add = false)
|
||||
public function Summary(int $maxWords = 50, string|false $add = false): string
|
||||
{
|
||||
// Get plain-text version
|
||||
$value = $this->Plain();
|
||||
@ -171,10 +160,8 @@ class DBText extends DBString
|
||||
|
||||
/**
|
||||
* Get first paragraph
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function FirstParagraph()
|
||||
public function FirstParagraph(): string
|
||||
{
|
||||
$value = $this->Plain();
|
||||
if (empty($value)) {
|
||||
@ -193,17 +180,15 @@ class DBText extends DBString
|
||||
* @param int $characters Number of characters in the summary
|
||||
* @param string $keywords Supplied string ("keywords"). Will fall back to 'Search' querystring arg.
|
||||
* @param bool $highlight Add a highlight <mark> element around search query?
|
||||
* @param string|false $prefix Prefix text
|
||||
* @param string|false $suffix Suffix text
|
||||
* @return string HTML string with context
|
||||
*/
|
||||
public function ContextSummary(
|
||||
$characters = 500,
|
||||
$keywords = null,
|
||||
$highlight = true,
|
||||
$prefix = false,
|
||||
$suffix = false
|
||||
) {
|
||||
int $characters = 500,
|
||||
?string $keywords = null,
|
||||
bool $highlight = true,
|
||||
string|false $prefix = false,
|
||||
string|false $suffix = false
|
||||
): string {
|
||||
|
||||
if (!$keywords) {
|
||||
// Use the default "Search" request variable (from SearchForm)
|
||||
@ -267,7 +252,7 @@ class DBText extends DBString
|
||||
return nl2br($summary ?? '');
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null, $params = null)
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
if (!$this->nullifyEmpty) {
|
||||
// Allow the user to select if it's null instead of automatically assuming empty string is
|
||||
@ -277,7 +262,7 @@ class DBText extends DBString
|
||||
return TextareaField::create($this->name, $title);
|
||||
}
|
||||
|
||||
public function scaffoldSearchField($title = null)
|
||||
public function scaffoldSearchField(?string $title = null): ?FormField
|
||||
{
|
||||
return new TextField($this->name, $title);
|
||||
}
|
||||
|
@ -4,11 +4,13 @@ namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use IntlDateFormatter;
|
||||
use InvalidArgumentException;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\Forms\TimeField;
|
||||
use SilverStripe\i18n\i18n;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\Security\Member;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\View\ViewableData;
|
||||
|
||||
/**
|
||||
* Represents a column in the database with the type 'Time'.
|
||||
@ -25,9 +27,9 @@ class DBTime extends DBField
|
||||
/**
|
||||
* Standard ISO format string for time in CLDR standard format
|
||||
*/
|
||||
const ISO_TIME = 'HH:mm:ss';
|
||||
public const ISO_TIME = 'HH:mm:ss';
|
||||
|
||||
public function setValue($value, $record = null, $markChanged = true)
|
||||
public function setValue(mixed $value, null|array|ViewableData $record = null, bool $markChanged = true): static
|
||||
{
|
||||
$value = $this->parseTime($value);
|
||||
if ($value === false) {
|
||||
@ -42,10 +44,9 @@ class DBTime extends DBField
|
||||
/**
|
||||
* Parse timestamp or iso8601-ish date into standard iso8601 format
|
||||
*
|
||||
* @param mixed $value
|
||||
* @return string|null|false Formatted time, null if empty but valid, or false if invalid
|
||||
*/
|
||||
protected function parseTime($value)
|
||||
protected function parseTime(mixed $value): string|null|false
|
||||
{
|
||||
// Skip empty values
|
||||
if (empty($value) && !is_numeric($value)) {
|
||||
@ -73,24 +74,19 @@ class DBTime extends DBField
|
||||
|
||||
/**
|
||||
* Get date / time formatter for the current locale
|
||||
*
|
||||
* @param int $timeLength
|
||||
* @return IntlDateFormatter
|
||||
*/
|
||||
public function getFormatter($timeLength = IntlDateFormatter::MEDIUM)
|
||||
public function getFormatter(int $timeLength = IntlDateFormatter::MEDIUM): IntlDateFormatter
|
||||
{
|
||||
return IntlDateFormatter::create(i18n::get_locale(), IntlDateFormatter::NONE, $timeLength);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the date in the localised short format
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function Short()
|
||||
public function Short(): string
|
||||
{
|
||||
if (!$this->value) {
|
||||
return null;
|
||||
return '';
|
||||
}
|
||||
$formatter = $this->getFormatter(IntlDateFormatter::SHORT);
|
||||
return $formatter->format($this->getTimestamp());
|
||||
@ -99,13 +95,11 @@ class DBTime extends DBField
|
||||
/**
|
||||
* Returns the standard localised medium time
|
||||
* e.g. "3:15pm"
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function Nice()
|
||||
public function Nice(): string
|
||||
{
|
||||
if (!$this->value) {
|
||||
return null;
|
||||
return '';
|
||||
}
|
||||
$formatter = $this->getFormatter();
|
||||
return $formatter->format($this->getTimestamp());
|
||||
@ -114,20 +108,19 @@ class DBTime extends DBField
|
||||
/**
|
||||
* Return the time using a particular formatting string.
|
||||
*
|
||||
* @param string $format Format code string. See https://unicode-org.github.io/icu/userguide/format_parse/datetime
|
||||
* @return string The time in the requested format
|
||||
* See https://unicode-org.github.io/icu/userguide/format_parse/datetime for valid formats
|
||||
*/
|
||||
public function Format($format)
|
||||
public function Format(string $format): string
|
||||
{
|
||||
if (!$this->value) {
|
||||
return null;
|
||||
return '';
|
||||
}
|
||||
$formatter = $this->getFormatter();
|
||||
$formatter->setPattern($format);
|
||||
return $formatter->format($this->getTimestamp());
|
||||
}
|
||||
|
||||
public function requireField()
|
||||
public function requireField(): void
|
||||
{
|
||||
$parts = [
|
||||
'datatype' => 'time',
|
||||
@ -140,18 +133,15 @@ class DBTime extends DBField
|
||||
DB::require_field($this->tableName, $this->name, $values);
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null, $params = null)
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
return TimeField::create($this->name, $title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a time formatted as per a CMS user's settings.
|
||||
*
|
||||
* @param Member $member
|
||||
* @return string A time formatted as per user-defined settings.
|
||||
*/
|
||||
public function FormatFromSettings($member = null)
|
||||
public function FormatFromSettings(?Member $member = null): string
|
||||
{
|
||||
if (!$member) {
|
||||
$member = Security::getCurrentUser();
|
||||
@ -169,20 +159,16 @@ class DBTime extends DBField
|
||||
|
||||
/**
|
||||
* Get standard ISO time format string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getISOFormat()
|
||||
public function getISOFormat(): string
|
||||
{
|
||||
return DBTime::ISO_TIME;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get unix timestamp for this time
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getTimestamp()
|
||||
public function getTimestamp(): int
|
||||
{
|
||||
if ($this->value) {
|
||||
return strtotime($this->value ?? '');
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\Forms\NullableField;
|
||||
use SilverStripe\Forms\TextField;
|
||||
use SilverStripe\ORM\Connect\MySQLDatabase;
|
||||
@ -17,18 +18,15 @@ use SilverStripe\ORM\DB;
|
||||
*/
|
||||
class DBVarchar extends DBString
|
||||
{
|
||||
|
||||
private static $casting = [
|
||||
private static array $casting = [
|
||||
'Initial' => 'Text',
|
||||
'URL' => 'Text',
|
||||
];
|
||||
|
||||
/**
|
||||
* Max size of this field
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $size;
|
||||
protected int $size;
|
||||
|
||||
/**
|
||||
* Construct a new short text field
|
||||
@ -38,7 +36,7 @@ class DBVarchar extends DBString
|
||||
* @param array $options Optional parameters, e.g. array("nullifyEmpty"=>false).
|
||||
* See {@link StringField::setOptions()} for information on the available options
|
||||
*/
|
||||
public function __construct($name = null, $size = 255, $options = [])
|
||||
public function __construct(?string $name = null, int $size = 255, array $options = [])
|
||||
{
|
||||
$this->size = $size ? $size : 255;
|
||||
parent::__construct($name, $options);
|
||||
@ -53,16 +51,12 @@ class DBVarchar extends DBString
|
||||
*
|
||||
* @return int The size of the field
|
||||
*/
|
||||
public function getSize()
|
||||
public function getSize(): int
|
||||
{
|
||||
return $this->size;
|
||||
}
|
||||
|
||||
/**
|
||||
* (non-PHPdoc)
|
||||
* @see DBField::requireField()
|
||||
*/
|
||||
public function requireField()
|
||||
public function requireField(): void
|
||||
{
|
||||
$charset = Config::inst()->get(MySQLDatabase::class, 'charset');
|
||||
$collation = Config::inst()->get(MySQLDatabase::class, 'collation');
|
||||
@ -85,24 +79,20 @@ class DBVarchar extends DBString
|
||||
|
||||
/**
|
||||
* Return the first letter of the string followed by a .
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function Initial()
|
||||
public function Initial(): string
|
||||
{
|
||||
if ($this->exists()) {
|
||||
$value = $this->RAW();
|
||||
return $value[0] . '.';
|
||||
}
|
||||
return null;
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure that the given value is an absolute URL.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function URL()
|
||||
public function URL(): string
|
||||
{
|
||||
$value = $this->RAW();
|
||||
if (preg_match('#^[a-zA-Z]+://#', $value ?? '')) {
|
||||
@ -113,14 +103,13 @@ class DBVarchar extends DBString
|
||||
|
||||
/**
|
||||
* Return the value of the field in rich text format
|
||||
* @return string
|
||||
*/
|
||||
public function RTF()
|
||||
public function RTF(): string
|
||||
{
|
||||
return str_replace("\n", '\par ', $this->RAW() ?? '');
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null, $params = null)
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
// Set field with appropriate size
|
||||
$field = TextField::create($this->name, $title);
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use SilverStripe\Forms\DropdownField;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\ORM\DB;
|
||||
|
||||
/**
|
||||
@ -10,15 +11,14 @@ use SilverStripe\ORM\DB;
|
||||
*/
|
||||
class DBYear extends DBField
|
||||
{
|
||||
|
||||
public function requireField()
|
||||
public function requireField(): void
|
||||
{
|
||||
$parts = ['datatype' => 'year', 'precision' => 4, 'arrayValue' => $this->arrayValue];
|
||||
$values = ['type' => 'year', 'parts' => $parts];
|
||||
DB::require_field($this->tableName, $this->name, $values);
|
||||
}
|
||||
|
||||
public function scaffoldFormField($title = null, $params = null)
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
$selectBox = DropdownField::create($this->name, $title);
|
||||
$selectBox->setSource($this->getDefaultOptions());
|
||||
@ -31,11 +31,10 @@ class DBYear extends DBField
|
||||
* input values. Starts by default at the current year,
|
||||
* and counts back to 1900.
|
||||
*
|
||||
* @param int|bool $start starting date to count down from
|
||||
* @param int|bool $end end date to count down to
|
||||
* @return array
|
||||
* @param int|null $start starting date to count down from
|
||||
* @param int|null $end end date to count down to
|
||||
*/
|
||||
private function getDefaultOptions($start = null, $end = null)
|
||||
private function getDefaultOptions(?int $start = null, ?int $end = null): array
|
||||
{
|
||||
if (!$start) {
|
||||
$start = (int)date('Y');
|
||||
|
@ -112,7 +112,7 @@ abstract class ListDecorator extends ViewableData implements SS_List, Sortable,
|
||||
return $this->list->getIterator();
|
||||
}
|
||||
|
||||
public function exists()
|
||||
public function exists(): bool
|
||||
{
|
||||
return $this->list->exists();
|
||||
}
|
||||
@ -140,7 +140,7 @@ abstract class ListDecorator extends ViewableData implements SS_List, Sortable,
|
||||
return $this->list->count();
|
||||
}
|
||||
|
||||
public function forTemplate()
|
||||
public function forTemplate(): string
|
||||
{
|
||||
return $this->list->forTemplate();
|
||||
}
|
||||
@ -313,7 +313,7 @@ abstract class ListDecorator extends ViewableData implements SS_List, Sortable,
|
||||
return $this->list->exclude(...func_get_args());
|
||||
}
|
||||
|
||||
public function debug()
|
||||
public function debug(): string
|
||||
{
|
||||
return $this->list->debug();
|
||||
}
|
||||
|
@ -70,13 +70,10 @@ class ArrayData extends ViewableData
|
||||
*
|
||||
* If the value is an associative array, it will likewise be
|
||||
* converted recursively to an ArrayData.
|
||||
*
|
||||
* @param string $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function getField($field)
|
||||
public function getField(string $fieldName): mixed
|
||||
{
|
||||
$value = $this->array[$field];
|
||||
$value = $this->array[$fieldName];
|
||||
if (is_object($value) && !($value instanceof ViewableData) && !is_iterable($value)) {
|
||||
return new ArrayData($value);
|
||||
} elseif (ArrayLib::is_associative($value)) {
|
||||
@ -87,14 +84,10 @@ class ArrayData extends ViewableData
|
||||
}
|
||||
/**
|
||||
* Add or set a field on this object.
|
||||
*
|
||||
* @param string $field
|
||||
* @param mixed $value
|
||||
* @return $this
|
||||
*/
|
||||
public function setField($field, $value)
|
||||
public function setField(string $fieldName, mixed $value): static
|
||||
{
|
||||
$this->array[$field] = $value;
|
||||
$this->array[$fieldName] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
@ -104,9 +97,9 @@ class ArrayData extends ViewableData
|
||||
* @param string $field Field Key
|
||||
* @return bool
|
||||
*/
|
||||
public function hasField($field)
|
||||
public function hasField(string $fieldName): bool
|
||||
{
|
||||
return isset($this->array[$field]);
|
||||
return isset($this->array[$fieldName]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -46,10 +46,7 @@ class HTMLValue extends ViewableData
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getContent()
|
||||
public function getContent(): string
|
||||
{
|
||||
$document = $this->getDocument();
|
||||
if (!$document) {
|
||||
@ -98,7 +95,7 @@ class HTMLValue extends ViewableData
|
||||
}
|
||||
|
||||
/** @see HTMLValue::getContent() */
|
||||
public function forTemplate()
|
||||
public function forTemplate(): string
|
||||
{
|
||||
return $this->getContent();
|
||||
}
|
||||
|
@ -733,6 +733,6 @@ class ShortcodeParser
|
||||
|
||||
$this->extend('onAfterParse', $content);
|
||||
|
||||
return $content;
|
||||
return $content ?? '';
|
||||
}
|
||||
}
|
||||
|
@ -288,7 +288,7 @@ class SSTemplateParser extends Parser implements TemplateParser
|
||||
$arguments = $sub['Call']['CallArguments']['php'];
|
||||
$res['php'] .= "->$method('$property', [$arguments], true)";
|
||||
} else {
|
||||
$res['php'] .= "->$method('$property', null, true)";
|
||||
$res['php'] .= "->$method('$property', [], true)";
|
||||
}
|
||||
}
|
||||
|
||||
@ -1037,7 +1037,7 @@ class SSTemplateParser extends Parser implements TemplateParser
|
||||
|
||||
//loop without arguments loops on the current scope
|
||||
if ($res['ArgumentCount'] == 0) {
|
||||
$on = '$scope->locally()->obj(\'Me\', null, true)';
|
||||
$on = '$scope->locally()->obj(\'Me\', [], true)';
|
||||
} else { //loop in the normal way
|
||||
$arg = $res['Arguments'][0];
|
||||
if ($arg['ArgumentMode'] == 'string') {
|
||||
|
@ -779,7 +779,7 @@ class SSTemplateParser extends Parser implements TemplateParser
|
||||
$arguments = $sub['Call']['CallArguments']['php'];
|
||||
$res['php'] .= "->$method('$property', [$arguments], true)";
|
||||
} else {
|
||||
$res['php'] .= "->$method('$property', null, true)";
|
||||
$res['php'] .= "->$method('$property', [], true)";
|
||||
}
|
||||
}
|
||||
|
||||
@ -1886,6 +1886,8 @@ class SSTemplateParser extends Parser implements TemplateParser
|
||||
$res['php'] .= '((bool)'.$sub['php'].')';
|
||||
} else {
|
||||
$php = ($sub['ArgumentMode'] == 'default' ? $sub['lookup_php'] : $sub['php']);
|
||||
// TODO: kinda hacky - maybe we need a way to pass state down the parse chain so
|
||||
// Lookup_LastLookupStep and Argument_BareWord can produce hasValue instead of XML_val
|
||||
$res['php'] .= str_replace('$$FINAL', 'hasValue', $php ?? '');
|
||||
}
|
||||
}
|
||||
@ -4263,7 +4265,7 @@ class SSTemplateParser extends Parser implements TemplateParser
|
||||
|
||||
//loop without arguments loops on the current scope
|
||||
if ($res['ArgumentCount'] == 0) {
|
||||
$on = '$scope->locally()->obj(\'Me\', null, true)';
|
||||
$on = '$scope->locally()->obj(\'Me\', [], true)';
|
||||
} else { //loop in the normal way
|
||||
$arg = $res['Arguments'][0];
|
||||
if ($arg['ArgumentMode'] == 'string') {
|
||||
@ -5290,6 +5292,8 @@ class SSTemplateParser extends Parser implements TemplateParser
|
||||
$text = stripslashes($text ?? '');
|
||||
$text = addcslashes($text ?? '', '\'\\');
|
||||
|
||||
// TODO: This is pretty ugly & gets applied on all files not just html. I wonder if we can make this
|
||||
// non-dynamically calculated
|
||||
$code = <<<'EOC'
|
||||
(\SilverStripe\View\SSViewer::getRewriteHashLinksDefault()
|
||||
? \SilverStripe\Core\Convert::raw2att( preg_replace("/^(\\/)+/", "/", $_SERVER['REQUEST_URI'] ) )
|
||||
@ -5328,7 +5332,8 @@ EOC;
|
||||
|
||||
$this->includeDebuggingComments = $includeDebuggingComments;
|
||||
|
||||
// Ignore UTF8 BOM at beginning of string.
|
||||
// Ignore UTF8 BOM at beginning of string. TODO: Confirm this is needed, make sure SSViewer handles UTF
|
||||
// (and other encodings) properly
|
||||
if (substr($string ?? '', 0, 3) == pack("CCC", 0xef, 0xbb, 0xbf)) {
|
||||
$this->pos = 3;
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
namespace SilverStripe\View;
|
||||
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
|
||||
/**
|
||||
* Special SSViewer that will process a template passed as a string, rather than a filename.
|
||||
@ -71,7 +72,9 @@ class SSViewer_FromString extends SSViewer
|
||||
unlink($cacheFile ?? '');
|
||||
}
|
||||
|
||||
return $val;
|
||||
$html = DBField::create_field('HTMLFragment', $val);
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2,29 +2,23 @@
|
||||
|
||||
namespace SilverStripe\View;
|
||||
|
||||
use ArrayIterator;
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use IteratorAggregate;
|
||||
use LogicException;
|
||||
use ReflectionMethod;
|
||||
use ReflectionObject;
|
||||
use ReflectionProperty;
|
||||
use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Core\Config\Configurable;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Core\Extensible;
|
||||
use SilverStripe\Core\Injector\Injectable;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Dev\Debug;
|
||||
use SilverStripe\Dev\Deprecation;
|
||||
use SilverStripe\ORM\ArrayLib;
|
||||
use SilverStripe\ORM\ArrayList;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBHTMLText;
|
||||
use SilverStripe\View\SSViewer;
|
||||
use Traversable;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
@ -34,7 +28,7 @@ use UnexpectedValueException;
|
||||
* is provided and automatically escaped by ViewableData. Any class that needs to be available to a view (controllers,
|
||||
* {@link DataObject}s, page controls) should inherit from this class.
|
||||
*/
|
||||
class ViewableData implements IteratorAggregate
|
||||
class ViewableData
|
||||
{
|
||||
use Extensible {
|
||||
defineMethods as extensibleDefineMethods;
|
||||
@ -50,27 +44,18 @@ class ViewableData implements IteratorAggregate
|
||||
* 'FieldName' => 'ClassToCastTo(Arguments)'
|
||||
* );
|
||||
* </code>
|
||||
*
|
||||
* @var array
|
||||
* @config
|
||||
*/
|
||||
private static $casting = [
|
||||
private static array $casting = [
|
||||
'CSSClasses' => 'Varchar'
|
||||
];
|
||||
|
||||
/**
|
||||
* The default object to cast scalar fields to if casting information is not specified, and casting to an object
|
||||
* is required.
|
||||
*
|
||||
* @var string
|
||||
* @config
|
||||
*/
|
||||
private static $default_cast = 'Text';
|
||||
private static string $default_cast = 'Text';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $casting_cache = [];
|
||||
private static array $casting_cache = [];
|
||||
|
||||
/**
|
||||
* Acts as a PHP 8.2+ compliant replacement for dynamic properties
|
||||
@ -81,20 +66,12 @@ class ViewableData implements IteratorAggregate
|
||||
|
||||
/**
|
||||
* A failover object to attempt to get data from if it is not present on this object.
|
||||
*
|
||||
* @var ViewableData
|
||||
*/
|
||||
protected $failover;
|
||||
protected ?ViewableData $failover = null;
|
||||
|
||||
/**
|
||||
* @var ViewableData
|
||||
*/
|
||||
protected $customisedObject;
|
||||
protected ?ViewableData $customisedObject = null;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $objCache = [];
|
||||
private array $objCache = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
@ -108,11 +85,8 @@ class ViewableData implements IteratorAggregate
|
||||
* Check if a field exists on this object or its failover.
|
||||
* Note that, unlike the core isset() implementation, this will return true if the property is defined
|
||||
* and set to null.
|
||||
*
|
||||
* @param string $property
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($property)
|
||||
public function __isset(string $property): bool
|
||||
{
|
||||
// getField() isn't a field-specific getter and shouldn't be treated as such
|
||||
if (strtolower($property ?? '') !== 'field' && $this->hasMethod("get$property")) {
|
||||
@ -131,11 +105,8 @@ class ViewableData implements IteratorAggregate
|
||||
/**
|
||||
* Get the value of a property/field on this object. This will check if a method called get{$property} exists, then
|
||||
* check if a field is available using {@link ViewableData::getField()}, then fall back on a failover object.
|
||||
*
|
||||
* @param string $property
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($property)
|
||||
public function __get(string $property): mixed
|
||||
{
|
||||
// getField() isn't a field-specific getter and shouldn't be treated as such
|
||||
$method = "get$property";
|
||||
@ -155,11 +126,8 @@ class ViewableData implements IteratorAggregate
|
||||
/**
|
||||
* Set a property/field on this object. This will check for the existence of a method called set{$property}, then
|
||||
* use the {@link ViewableData::setField()} method.
|
||||
*
|
||||
* @param string $property
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function __set($property, $value)
|
||||
public function __set(string $property, mixed $value): void
|
||||
{
|
||||
$this->objCacheClear();
|
||||
$method = "set$property";
|
||||
@ -173,10 +141,8 @@ class ViewableData implements IteratorAggregate
|
||||
|
||||
/**
|
||||
* Set a failover object to attempt to get data from if it is not present on this object.
|
||||
*
|
||||
* @param ViewableData $failover
|
||||
*/
|
||||
public function setFailover(ViewableData $failover)
|
||||
public function setFailover(ViewableData $failover): void
|
||||
{
|
||||
// Ensure cached methods from previous failover are removed
|
||||
if ($this->failover) {
|
||||
@ -189,56 +155,44 @@ class ViewableData implements IteratorAggregate
|
||||
|
||||
/**
|
||||
* Get the current failover object if set
|
||||
*
|
||||
* @return ViewableData|null
|
||||
*/
|
||||
public function getFailover()
|
||||
public function getFailover(): ?ViewableData
|
||||
{
|
||||
return $this->failover;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a field exists on this object. This should be overloaded in child classes.
|
||||
*
|
||||
* @param string $field
|
||||
* @return bool
|
||||
*/
|
||||
public function hasField($field)
|
||||
public function hasField(string $fieldName): bool
|
||||
{
|
||||
return property_exists($this, $field) || $this->hasDynamicData($field);
|
||||
return property_exists($this, $fieldName) || $this->hasDynamicData($fieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the value of a field on this object. This should be overloaded in child classes.
|
||||
*
|
||||
* @param string $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function getField($field)
|
||||
public function getField(string $fieldName): mixed
|
||||
{
|
||||
if ($this->isAccessibleProperty($field)) {
|
||||
return $this->$field;
|
||||
if ($this->isAccessibleProperty($fieldName)) {
|
||||
return $this->$fieldName;
|
||||
}
|
||||
return $this->getDynamicData($field);
|
||||
return $this->getDynamicData($fieldName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a field on this object. This should be overloaded in child classes.
|
||||
*
|
||||
* @param string $field
|
||||
* @param mixed $value
|
||||
* @return $this
|
||||
*/
|
||||
public function setField($field, $value)
|
||||
public function setField(string $fieldName, mixed $value): static
|
||||
{
|
||||
$this->objCacheClear();
|
||||
// prior to PHP 8.2 support ViewableData::setField() simply used `$this->field = $value;`
|
||||
// so the following logic essentially mimics this behaviour, though without the use
|
||||
// of now deprecated dynamic properties
|
||||
if ($this->isAccessibleProperty($field)) {
|
||||
$this->$field = $value;
|
||||
if ($this->isAccessibleProperty($fieldName)) {
|
||||
$this->$fieldName = $value;
|
||||
}
|
||||
return $this->setDynamicData($field, $value);
|
||||
return $this->setDynamicData($fieldName, $value);
|
||||
}
|
||||
|
||||
public function getDynamicData(string $field): mixed
|
||||
@ -322,11 +276,8 @@ class ViewableData implements IteratorAggregate
|
||||
* with references to both this and the new custom data.
|
||||
*
|
||||
* Note that any fields you specify will take precedence over the fields on this object.
|
||||
*
|
||||
* @param array|ViewableData $data
|
||||
* @return ViewableData_Customised
|
||||
*/
|
||||
public function customise($data)
|
||||
public function customise(array|ViewableData $data): ViewableData
|
||||
{
|
||||
if (is_array($data) && (empty($data) || ArrayLib::is_associative($data))) {
|
||||
$data = new ArrayData($data);
|
||||
@ -346,33 +297,25 @@ class ViewableData implements IteratorAggregate
|
||||
*
|
||||
* This method should be overridden in subclasses to provide more context about the classes state. For example, a
|
||||
* {@link DataObject} class could return false when it is deleted from the database
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function exists()
|
||||
public function exists(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string the class name
|
||||
* Return the class name (though subclasses may return something else)
|
||||
*/
|
||||
public function __toString()
|
||||
public function __toString(): string
|
||||
{
|
||||
return static::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ViewableData
|
||||
*/
|
||||
public function getCustomisedObj()
|
||||
public function getCustomisedObj(): ?ViewableData
|
||||
{
|
||||
return $this->customisedObject;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ViewableData $object
|
||||
*/
|
||||
public function setCustomisedObj(ViewableData $object)
|
||||
{
|
||||
$this->customisedObject = $object;
|
||||
@ -384,12 +327,11 @@ class ViewableData implements IteratorAggregate
|
||||
* 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.
|
||||
*
|
||||
* @param string $field
|
||||
* @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.
|
||||
* @throws Exception
|
||||
*/
|
||||
public function castingHelper($field, bool $useFallback = true)
|
||||
public function castingHelper(string $field, bool $useFallback = true): ?string
|
||||
{
|
||||
// Get casting if it has been configured.
|
||||
// DB fields and PHP methods are all case insensitive so we normalise casing before checking.
|
||||
@ -441,11 +383,8 @@ class ViewableData implements IteratorAggregate
|
||||
|
||||
/**
|
||||
* Get the class name a field on this object will be casted to.
|
||||
*
|
||||
* @param string $field
|
||||
* @return string
|
||||
*/
|
||||
public function castingClass($field)
|
||||
public function castingClass(string $field): string
|
||||
{
|
||||
// Strip arguments
|
||||
$spec = $this->castingHelper($field);
|
||||
@ -455,10 +394,9 @@ class ViewableData implements IteratorAggregate
|
||||
/**
|
||||
* Return the string-format type for the given field.
|
||||
*
|
||||
* @param string $field
|
||||
* @return string 'xml'|'raw'
|
||||
*/
|
||||
public function escapeTypeForField($field)
|
||||
public function escapeTypeForField(string $field): string
|
||||
{
|
||||
$class = $this->castingClass($field) ?: $this->config()->get('default_cast');
|
||||
|
||||
@ -477,10 +415,9 @@ class ViewableData implements IteratorAggregate
|
||||
* - an SSViewer instance
|
||||
*
|
||||
* @param string|array|SSViewer $template the template to render into
|
||||
* @param array $customFields fields to customise() the object with before rendering
|
||||
* @return DBHTMLText
|
||||
* @param ViewableData|array|null $customFields fields to customise() the object with before rendering
|
||||
*/
|
||||
public function renderWith($template, $customFields = null)
|
||||
public function renderWith($template, ViewableData|array|null $customFields = null): DBHTMLText
|
||||
{
|
||||
if (!is_object($template)) {
|
||||
$template = SSViewer::create($template);
|
||||
@ -556,14 +493,18 @@ class ViewableData implements IteratorAggregate
|
||||
* Get the value of a field on this object, automatically inserting the value into any available casting objects
|
||||
* that have been specified.
|
||||
*
|
||||
* @param string $fieldName
|
||||
* @param array $arguments
|
||||
* @param bool $cache Cache this object
|
||||
* @param string $cacheName a custom cache name
|
||||
* @return object|DBField
|
||||
* @return object|DBField|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
|
||||
* be returned.
|
||||
*/
|
||||
public function obj($fieldName, $arguments = [], $cache = false, $cacheName = null)
|
||||
{
|
||||
public function obj(
|
||||
string $fieldName,
|
||||
array $arguments = [],
|
||||
bool $cache = false,
|
||||
?string $cacheName = null
|
||||
): ?object {
|
||||
$hasObj = false;
|
||||
if (!$cacheName && $cache) {
|
||||
$cacheName = $this->objCacheName($fieldName, $arguments);
|
||||
}
|
||||
@ -576,11 +517,19 @@ class ViewableData implements IteratorAggregate
|
||||
|
||||
// Load value from record
|
||||
if ($this->hasMethod($fieldName)) {
|
||||
$hasObj = true;
|
||||
$value = call_user_func_array([$this, $fieldName], $arguments ?: []);
|
||||
} else {
|
||||
$hasObj = $this->hasField($fieldName) || ($this->hasMethod("get{$fieldName}") && $this->isAccessibleMethod("get{$fieldName}"));
|
||||
$value = $this->$fieldName;
|
||||
}
|
||||
|
||||
// Return null early if there's no backing for this field
|
||||
// i.e. no poperty, no method, etc - it just doesn't exist on this model.
|
||||
if (!$hasObj && $value === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Try to cast object if we have an explicit cast set
|
||||
if (!is_object($value)) {
|
||||
$castingHelper = $this->castingHelper($fieldName, false);
|
||||
@ -617,26 +566,18 @@ class ViewableData implements IteratorAggregate
|
||||
* A simple wrapper around {@link ViewableData::obj()} that automatically caches the result so it can be used again
|
||||
* without re-running the method.
|
||||
*
|
||||
* @param string $fieldName
|
||||
* @param array $arguments
|
||||
* @param string $identifier an optional custom cache identifier
|
||||
* @return Object|DBField
|
||||
*/
|
||||
public function cachedCall($fieldName, $arguments = [], $identifier = null)
|
||||
public function cachedCall(string $fieldName, array $arguments = [], ?string $cacheName = null): object
|
||||
{
|
||||
return $this->obj($fieldName, $arguments, true, $identifier);
|
||||
return $this->obj($fieldName, $arguments, true, $cacheName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if a given method/field has a valid value. If the result is an object, this will return the result of the
|
||||
* exists method, otherwise will check if the result is not just an empty paragraph tag.
|
||||
*
|
||||
* @param string $field
|
||||
* @param array $arguments
|
||||
* @param bool $cache
|
||||
* @return bool
|
||||
*/
|
||||
public function hasValue($field, $arguments = [], $cache = true)
|
||||
public function hasValue(string $field, array $arguments = [], bool $cache = true): bool
|
||||
{
|
||||
$result = $this->obj($field, $arguments, $cache);
|
||||
if ($result instanceof ViewableData) {
|
||||
@ -648,15 +589,13 @@ class ViewableData implements IteratorAggregate
|
||||
/**
|
||||
* Get the string value of a field on this object that has been suitable escaped to be inserted directly into a
|
||||
* template.
|
||||
*
|
||||
* @param string $field
|
||||
* @param array $arguments
|
||||
* @param bool $cache
|
||||
* @return string
|
||||
*/
|
||||
public function XML_val($field, $arguments = [], $cache = false)
|
||||
public function XML_val(string $field, array $arguments = [], bool $cache = false): string
|
||||
{
|
||||
$result = $this->obj($field, $arguments, $cache);
|
||||
if (!$result) {
|
||||
return '';
|
||||
}
|
||||
// Might contain additional formatting over ->XML(). E.g. parse shortcodes, nl2br()
|
||||
return $result->forTemplate();
|
||||
}
|
||||
@ -665,9 +604,8 @@ class ViewableData implements IteratorAggregate
|
||||
* Get an array of XML-escaped values by field name
|
||||
*
|
||||
* @param array $fields an array of field names
|
||||
* @return array
|
||||
*/
|
||||
public function getXMLValues($fields)
|
||||
public function getXMLValues(array $fields): array
|
||||
{
|
||||
$result = [];
|
||||
|
||||
@ -678,33 +616,12 @@ class ViewableData implements IteratorAggregate
|
||||
return $result;
|
||||
}
|
||||
|
||||
// ITERATOR SUPPORT ------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Return a single-item iterator so you can iterate over the fields of a single record.
|
||||
*
|
||||
* This is useful so you can use a single record inside a <% control %> block in a template - and then use
|
||||
* to access individual fields on this object.
|
||||
*
|
||||
* @deprecated 5.2.0 Will be removed without equivalent functionality
|
||||
*
|
||||
* @return ArrayIterator
|
||||
*/
|
||||
public function getIterator(): Traversable
|
||||
{
|
||||
Deprecation::notice('5.2.0', 'Will be removed without equivalent functionality');
|
||||
return new ArrayIterator([$this]);
|
||||
}
|
||||
|
||||
// UTILITY METHODS -------------------------------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Find appropriate templates for SSViewer to use to render this object
|
||||
*
|
||||
* @param string $suffix
|
||||
* @return array
|
||||
*/
|
||||
public function getViewerTemplates($suffix = '')
|
||||
public function getViewerTemplates(string $suffix = ''): array
|
||||
{
|
||||
return SSViewer::get_templates_by_class(static::class, $suffix, ViewableData::class);
|
||||
}
|
||||
@ -725,10 +642,9 @@ class ViewableData implements IteratorAggregate
|
||||
* stop point - e.g. "Page DataObject ViewableData".
|
||||
*
|
||||
* @param string $stopAtClass the class to stop at (default: ViewableData)
|
||||
* @return string
|
||||
* @uses ClassInfo
|
||||
*/
|
||||
public function CSSClasses($stopAtClass = ViewableData::class)
|
||||
public function CSSClasses(string $stopAtClass = ViewableData::class): string
|
||||
{
|
||||
$classes = [];
|
||||
$classAncestry = array_reverse(ClassInfo::ancestry(static::class) ?? []);
|
||||
@ -754,11 +670,9 @@ class ViewableData implements IteratorAggregate
|
||||
|
||||
/**
|
||||
* Return debug information about this object that can be rendered into a template
|
||||
*
|
||||
* @return ViewableData_Debugger
|
||||
*/
|
||||
public function Debug()
|
||||
public function Debug(): ViewableData|string
|
||||
{
|
||||
return new ViewableData_Debugger($this);
|
||||
return ViewableData_Debugger::create($this);
|
||||
}
|
||||
}
|
||||
|
@ -4,17 +4,12 @@ namespace SilverStripe\View;
|
||||
|
||||
class ViewableData_Customised extends ViewableData
|
||||
{
|
||||
protected ViewableData $original;
|
||||
|
||||
/**
|
||||
* @var ViewableData
|
||||
*/
|
||||
protected $original, $customised;
|
||||
protected ViewableData $customised;
|
||||
|
||||
/**
|
||||
* Instantiate a new customised ViewableData object
|
||||
*
|
||||
* @param ViewableData $originalObject
|
||||
* @param ViewableData $customisedObject
|
||||
*/
|
||||
public function __construct(ViewableData $originalObject, ViewableData $customisedObject)
|
||||
{
|
||||
@ -35,7 +30,7 @@ class ViewableData_Customised extends ViewableData
|
||||
return call_user_func_array([$this->original, $method], $arguments ?? []);
|
||||
}
|
||||
|
||||
public function __get($property)
|
||||
public function __get(string $property): mixed
|
||||
{
|
||||
if (isset($this->customised->$property)) {
|
||||
return $this->customised->$property;
|
||||
@ -44,12 +39,12 @@ class ViewableData_Customised extends ViewableData
|
||||
return $this->original->$property;
|
||||
}
|
||||
|
||||
public function __set($property, $value)
|
||||
public function __set(string $property, mixed $value): void
|
||||
{
|
||||
$this->customised->$property = $this->original->$property = $value;
|
||||
}
|
||||
|
||||
public function __isset($property)
|
||||
public function __isset(string $property): bool
|
||||
{
|
||||
return isset($this->customised->$property) || isset($this->original->$property) || parent::__isset($property);
|
||||
}
|
||||
@ -59,16 +54,20 @@ class ViewableData_Customised extends ViewableData
|
||||
return $this->customised->hasMethod($method) || $this->original->hasMethod($method);
|
||||
}
|
||||
|
||||
public function cachedCall($fieldName, $arguments = null, $identifier = null)
|
||||
public function cachedCall(string $fieldName, array $arguments = [], ?string $cacheName = null): object
|
||||
{
|
||||
if ($this->customisedHas($fieldName)) {
|
||||
return $this->customised->cachedCall($fieldName, $arguments, $identifier);
|
||||
return $this->customised->cachedCall($fieldName, $arguments, $cacheName);
|
||||
}
|
||||
return $this->original->cachedCall($fieldName, $arguments, $identifier);
|
||||
return $this->original->cachedCall($fieldName, $arguments, $cacheName);
|
||||
}
|
||||
|
||||
public function obj($fieldName, $arguments = null, $cache = false, $cacheName = null)
|
||||
{
|
||||
public function obj(
|
||||
string $fieldName,
|
||||
array $arguments = [],
|
||||
bool $cache = false,
|
||||
?string $cacheName = null
|
||||
): ?object {
|
||||
if ($this->customisedHas($fieldName)) {
|
||||
return $this->customised->obj($fieldName, $arguments, $cache, $cacheName);
|
||||
}
|
||||
|
@ -9,15 +9,8 @@ use ReflectionObject;
|
||||
*/
|
||||
class ViewableData_Debugger extends ViewableData
|
||||
{
|
||||
protected ViewableData $object;
|
||||
|
||||
/**
|
||||
* @var ViewableData
|
||||
*/
|
||||
protected $object;
|
||||
|
||||
/**
|
||||
* @param ViewableData $object
|
||||
*/
|
||||
public function __construct(ViewableData $object)
|
||||
{
|
||||
$this->object = $object;
|
||||
@ -25,9 +18,9 @@ class ViewableData_Debugger extends ViewableData
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string The rendered debugger
|
||||
* Returns the rendered debugger
|
||||
*/
|
||||
public function __toString()
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string)$this->forTemplate();
|
||||
}
|
||||
@ -35,11 +28,8 @@ class ViewableData_Debugger extends ViewableData
|
||||
/**
|
||||
* Return debugging information, as XHTML. If a field name is passed, it will show debugging information on that
|
||||
* field, otherwise it will show information on all methods and fields.
|
||||
*
|
||||
* @param string $field the field name
|
||||
* @return string
|
||||
*/
|
||||
public function forTemplate($field = null)
|
||||
public function forTemplate(?string $field = null): string
|
||||
{
|
||||
// debugging info for a specific field
|
||||
$class = get_class($this->object);
|
||||
|
@ -14,14 +14,14 @@ class TestObject extends ViewableData implements TestOnly
|
||||
$this->data = $data;
|
||||
}
|
||||
|
||||
public function hasField($name)
|
||||
public function hasField(string $fieldName): bool
|
||||
{
|
||||
return isset($this->data[$name]);
|
||||
return isset($this->data[$fieldName]);
|
||||
}
|
||||
|
||||
public function getField($name)
|
||||
public function getField(string $fieldName): mixed
|
||||
{
|
||||
return isset($this->data[$name]) ?: null;
|
||||
return isset($this->data[$fieldName]) ?: null;
|
||||
}
|
||||
|
||||
public function getSomething()
|
||||
|
@ -129,9 +129,9 @@ class DBClassNameTest extends SapphireTest
|
||||
$this->assertEquals('stdClass', $test3->getShortName());
|
||||
|
||||
$test4 = DBField::create_field('DBClassName', null);
|
||||
$this->assertNull($test4->getShortName());
|
||||
$this->assertSame('', $test4->getShortName());
|
||||
|
||||
$test5 = DBField::create_field('DBClassName', 'not a class');
|
||||
$this->assertNull($test5->getShortName());
|
||||
$this->assertSame('', $test5->getShortName());
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use SilverStripe\ORM\FieldType\DBMoney;
|
||||
|
||||
class DBDoubleMoney extends DBMoney implements TestOnly
|
||||
{
|
||||
public function writeToManipulation(&$manipulation)
|
||||
public function writeToManipulation(array &$manipulation): void
|
||||
{
|
||||
// Duplicate the amount before writing
|
||||
$this->setAmount($this->getAmount() * 2);
|
||||
|
@ -16,10 +16,10 @@ class TestDataObject extends DataObject implements TestOnly
|
||||
|
||||
public $setFieldCalledCount = 0;
|
||||
|
||||
public function setField($fieldName, $val)
|
||||
public function setField(string $fieldName, mixed $value): static
|
||||
{
|
||||
$this->setFieldCalledCount++;
|
||||
return parent::setField($fieldName, $val);
|
||||
return parent::setField($fieldName, $value);
|
||||
}
|
||||
|
||||
public function setMyTestField($val)
|
||||
|
@ -6,10 +6,11 @@ use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\View\ViewableData;
|
||||
|
||||
class TestDbField extends DBField implements TestOnly
|
||||
{
|
||||
public function requireField()
|
||||
public function requireField(): void
|
||||
{
|
||||
// Basically the same as DBVarchar but we don't want to test with DBVarchar in case something
|
||||
// changes in that class eventually.
|
||||
@ -34,9 +35,9 @@ class TestDbField extends DBField implements TestOnly
|
||||
|
||||
public $saveIntoCalledCount = 0;
|
||||
|
||||
public function saveInto($dataObject)
|
||||
public function saveInto(ViewableData $model): void
|
||||
{
|
||||
$this->saveIntoCalledCount++;
|
||||
return parent::saveInto($dataObject);
|
||||
parent::saveInto($model);
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use SilverStripe\ORM\FieldType\DBString;
|
||||
|
||||
class MyStringField extends DBString implements TestOnly
|
||||
{
|
||||
public function requireField()
|
||||
public function requireField(): void
|
||||
{
|
||||
}
|
||||
}
|
||||
|
@ -739,15 +739,15 @@ class DataObjectTest extends SapphireTest
|
||||
$fan1 = $this->objFromFixture(DataObjectTest\Fan::class, 'fan1');
|
||||
|
||||
// Test relation probing
|
||||
$this->assertFalse((bool)$team1->hasValue('Captain', null, false));
|
||||
$this->assertFalse((bool)$team1->hasValue('CaptainID', null, false));
|
||||
$this->assertFalse((bool)$team1->hasValue('Captain', [], false));
|
||||
$this->assertFalse((bool)$team1->hasValue('CaptainID', [], false));
|
||||
|
||||
// Add a captain to team 1
|
||||
$team1->setField('CaptainID', $player1->ID);
|
||||
$team1->write();
|
||||
|
||||
$this->assertTrue((bool)$team1->hasValue('Captain', null, false));
|
||||
$this->assertTrue((bool)$team1->hasValue('CaptainID', null, false));
|
||||
$this->assertTrue((bool)$team1->hasValue('Captain', [], false));
|
||||
$this->assertTrue((bool)$team1->hasValue('CaptainID', [], false));
|
||||
|
||||
$this->assertEquals(
|
||||
$player1->ID,
|
||||
@ -2075,22 +2075,22 @@ class DataObjectTest extends SapphireTest
|
||||
public function testHasValue()
|
||||
{
|
||||
$team = new DataObjectTest\Team();
|
||||
$this->assertFalse($team->hasValue('Title', null, false));
|
||||
$this->assertFalse($team->hasValue('DatabaseField', null, false));
|
||||
$this->assertFalse($team->hasValue('Title', [], false));
|
||||
$this->assertFalse($team->hasValue('DatabaseField', [], false));
|
||||
|
||||
$team->Title = 'hasValue';
|
||||
$this->assertTrue($team->hasValue('Title', null, false));
|
||||
$this->assertFalse($team->hasValue('DatabaseField', null, false));
|
||||
$this->assertTrue($team->hasValue('Title', [], false));
|
||||
$this->assertFalse($team->hasValue('DatabaseField', [], false));
|
||||
|
||||
$team->Title = '<p></p>';
|
||||
$this->assertTrue(
|
||||
$team->hasValue('Title', null, false),
|
||||
$team->hasValue('Title', [], false),
|
||||
'Test that an empty paragraph is a value for non-HTML fields.'
|
||||
);
|
||||
|
||||
$team->DatabaseField = 'hasValue';
|
||||
$this->assertTrue($team->hasValue('Title', null, false));
|
||||
$this->assertTrue($team->hasValue('DatabaseField', null, false));
|
||||
$this->assertTrue($team->hasValue('Title', [], false));
|
||||
$this->assertTrue($team->hasValue('DatabaseField', [], false));
|
||||
}
|
||||
|
||||
public function testHasMany()
|
||||
|
@ -34,10 +34,8 @@ class MockDynamicAssignmentDBField extends DBBoolean implements TestOnly
|
||||
|
||||
/**
|
||||
* If the field value and $dynamicAssignment are true, we'll try to do a dynamic assignment.
|
||||
* @param $value
|
||||
* @return array|int
|
||||
*/
|
||||
public function prepValueForDB($value)
|
||||
public function prepValueForDB(mixed $value): array|int|null
|
||||
{
|
||||
if ($value) {
|
||||
return $this->dynamicAssignment
|
||||
@ -48,7 +46,7 @@ class MockDynamicAssignmentDBField extends DBBoolean implements TestOnly
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function scalarValueOnly()
|
||||
public function scalarValueOnly(): bool
|
||||
{
|
||||
return $this->scalarOnly;
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ namespace SilverStripe\ORM\Tests;
|
||||
|
||||
use SilverStripe\Dev\SapphireTest;
|
||||
use SilverStripe\ORM\FieldType\DBDecimal;
|
||||
use TypeError;
|
||||
|
||||
class DecimalTest extends SapphireTest
|
||||
{
|
||||
@ -45,11 +46,8 @@ class DecimalTest extends SapphireTest
|
||||
|
||||
public function testInvalidSpecifiedDefaultValue()
|
||||
{
|
||||
$this->assertEquals(
|
||||
$this->testDataObject->MyDecimal3,
|
||||
0,
|
||||
'Invalid default value for Decimal type is casted to 0'
|
||||
);
|
||||
$this->expectException(TypeError::class);
|
||||
new DBDecimal(defaultValue: 'Invalid');
|
||||
}
|
||||
|
||||
public function testSpecifiedDefaultValueInDefaultsArray()
|
||||
|
@ -13,7 +13,6 @@ class TestObject extends DataObject implements TestOnly
|
||||
'Name' => 'Varchar',
|
||||
'MyDecimal1' => 'Decimal',
|
||||
'MyDecimal2' => 'Decimal(5,3,2.5)',
|
||||
'MyDecimal3' => 'Decimal(4,2,"Invalid default value")',
|
||||
'MyDecimal4' => 'Decimal',
|
||||
'MyDecimal5' => 'Decimal(20,18,0.99999999999999999999)',
|
||||
'MyDecimal6' => 'Decimal',
|
||||
|
@ -11,7 +11,7 @@ use stdClass;
|
||||
class ArrayDataTest extends SapphireTest
|
||||
{
|
||||
|
||||
public function testViewabledataItemsInsideArraydataArePreserved()
|
||||
public function testViewableDataItemsInsideArraydataArePreserved()
|
||||
{
|
||||
/* ViewableData objects will be preserved, but other objects will be converted */
|
||||
$arrayData = new ArrayData(
|
||||
|
@ -653,12 +653,14 @@ SS;
|
||||
|
||||
public function testLoopWhitespace()
|
||||
{
|
||||
$data = new ArrayList([new SSViewerTest\TestFixture()]);
|
||||
$this->assertEquals(
|
||||
'before[out:SingleItem.Test]after
|
||||
'before[out:Test]after
|
||||
beforeTestafter',
|
||||
$this->render(
|
||||
'before<% loop SingleItem %>$Test<% end_loop %>after
|
||||
before<% loop SingleItem %>Test<% end_loop %>after'
|
||||
'before<% loop %>$Test<% end_loop %>after
|
||||
before<% loop %>Test<% end_loop %>after',
|
||||
$data
|
||||
)
|
||||
);
|
||||
|
||||
@ -668,15 +670,16 @@ SS;
|
||||
$this->assertEquals(
|
||||
'before
|
||||
|
||||
[out:SingleItem.ItemOnItsOwnLine]
|
||||
[out:ItemOnItsOwnLine]
|
||||
|
||||
after',
|
||||
$this->render(
|
||||
'before
|
||||
<% loop SingleItem %>
|
||||
<% loop %>
|
||||
$ItemOnItsOwnLine
|
||||
<% end_loop %>
|
||||
after'
|
||||
after',
|
||||
$data
|
||||
)
|
||||
);
|
||||
|
||||
@ -2369,7 +2372,7 @@ EOC;
|
||||
public function testMe(): void
|
||||
{
|
||||
$mockArrayData = $this->getMockBuilder(ArrayData::class)->addMethods(['forTemplate'])->getMock();
|
||||
$mockArrayData->expects($this->once())->method('forTemplate');
|
||||
$mockArrayData->expects($this->once())->method('forTemplate')->willReturn('');
|
||||
$this->render('$Me', $mockArrayData);
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,6 @@ class TestFixture extends ViewableData
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
|
||||
private function argedName($fieldName, $arguments)
|
||||
{
|
||||
$childName = $this->name ? "$this->name.$fieldName" : $fieldName;
|
||||
@ -29,8 +28,12 @@ class TestFixture extends ViewableData
|
||||
}
|
||||
}
|
||||
|
||||
public function obj($fieldName, $arguments = null, $cache = false, $cacheName = null)
|
||||
{
|
||||
public function obj(
|
||||
string $fieldName,
|
||||
array $arguments = [],
|
||||
bool $cache = false,
|
||||
?string $cacheName = null
|
||||
): ?object {
|
||||
$childName = $this->argedName($fieldName, $arguments);
|
||||
|
||||
// Special field name Loop### to create a list
|
||||
@ -49,8 +52,7 @@ class TestFixture extends ViewableData
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function XML_val($fieldName, $arguments = null, $cache = false)
|
||||
public function XML_val(string $fieldName, array $arguments = [], bool $cache = false): string
|
||||
{
|
||||
if (preg_match('/NotSet/i', $fieldName ?? '')) {
|
||||
return '';
|
||||
@ -63,7 +65,7 @@ class TestFixture extends ViewableData
|
||||
}
|
||||
}
|
||||
|
||||
public function hasValue($fieldName, $arguments = null, $cache = true)
|
||||
public function hasValue(string $fieldName, array $arguments = [], bool $cache = true): bool
|
||||
{
|
||||
return (bool)$this->XML_val($fieldName, $arguments);
|
||||
}
|
||||
|
@ -133,7 +133,7 @@ class ViewableDataTest extends SapphireTest
|
||||
$this->assertFalse($data->hasValue('SomethingElse'));
|
||||
// this should cast the raw string to a StringField since we are
|
||||
// passing true as the third argument:
|
||||
$obj = $data->obj('Title', null, true);
|
||||
$obj = $data->obj('Title', [], true);
|
||||
$this->assertTrue(is_object($obj));
|
||||
// and the string field should have the value of the raw string:
|
||||
$this->assertEquals('SomeTitleValue', $obj->forTemplate());
|
||||
@ -164,11 +164,11 @@ class ViewableDataTest extends SapphireTest
|
||||
|
||||
// Save a literal string into cache
|
||||
$cache = true;
|
||||
$uncastedData = $obj->obj('noCastingInformation', null, false, $cache);
|
||||
$uncastedData = $obj->obj('noCastingInformation', [], false, $cache);
|
||||
|
||||
// Fetch the cached string as an object
|
||||
$forceReturnedObject = true;
|
||||
$castedData = $obj->obj('noCastingInformation', null, $forceReturnedObject);
|
||||
$castedData = $obj->obj('noCastingInformation', [], $forceReturnedObject);
|
||||
|
||||
// Uncasted data should always be the nonempty string
|
||||
$this->assertNotEmpty($uncastedData, 'Uncasted data was empty.');
|
||||
@ -189,15 +189,15 @@ class ViewableDataTest extends SapphireTest
|
||||
$objCached->Test = 'AAA';
|
||||
$objNotCached->Test = 'AAA';
|
||||
|
||||
$this->assertEquals('AAA', $objCached->obj('Test', null, true, true));
|
||||
$this->assertEquals('AAA', $objNotCached->obj('Test', null, true, true));
|
||||
$this->assertEquals('AAA', $objCached->obj('Test', [], true, true));
|
||||
$this->assertEquals('AAA', $objNotCached->obj('Test', [], true, true));
|
||||
|
||||
$objCached->Test = 'BBB';
|
||||
$objNotCached->Test = 'BBB';
|
||||
|
||||
// Cached data must be always the same
|
||||
$this->assertEquals('AAA', $objCached->obj('Test', null, true, true));
|
||||
$this->assertEquals('BBB', $objNotCached->obj('Test', null, true, true));
|
||||
$this->assertEquals('AAA', $objCached->obj('Test', [], true, true));
|
||||
$this->assertEquals('BBB', $objNotCached->obj('Test', [], true, true));
|
||||
}
|
||||
|
||||
public function testSetFailover()
|
||||
|
@ -50,7 +50,7 @@ class Castable extends ViewableData implements TestOnly
|
||||
return $this->unsafeXML();
|
||||
}
|
||||
|
||||
public function forTemplate()
|
||||
public function forTemplate(): string
|
||||
{
|
||||
return 'castable';
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use SilverStripe\View\ViewableData;
|
||||
class Caster extends ViewableData implements TestOnly
|
||||
{
|
||||
|
||||
public function forTemplate()
|
||||
public function forTemplate(): string
|
||||
{
|
||||
return 'casted';
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ class RequiresCasting extends ViewableData implements TestOnly
|
||||
|
||||
public $test = 'overwritten';
|
||||
|
||||
public function forTemplate()
|
||||
public function forTemplate(): string
|
||||
{
|
||||
return 'casted';
|
||||
}
|
||||
|
@ -15,7 +15,7 @@ class UnescapedCaster extends ViewableData implements TestOnly
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function forTemplate()
|
||||
public function forTemplate(): string
|
||||
{
|
||||
return Convert::raw2xml($this->value);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user