mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 12:05:37 +00:00
Compare commits
8 Commits
e46db939b3
...
da474707fb
Author | SHA1 | Date | |
---|---|---|---|
|
da474707fb | ||
|
fe46daa04f | ||
|
c523022cb9 | ||
|
a81b7855de | ||
|
e93dafb2fe | ||
|
6287b6ebeb | ||
|
c7ba8d19c5 | ||
|
5fa88663b0 |
@ -20,6 +20,8 @@ SilverStripe\Core\Injector\Injector:
|
||||
class: SilverStripe\ORM\FieldType\DBDecimal
|
||||
Double:
|
||||
class: SilverStripe\ORM\FieldType\DBDouble
|
||||
Email:
|
||||
class: SilverStripe\ORM\FieldType\DBEmail
|
||||
Enum:
|
||||
class: SilverStripe\ORM\FieldType\DBEnum
|
||||
Float:
|
||||
|
@ -13,6 +13,7 @@ use SilverStripe\Core\Extensible;
|
||||
use SilverStripe\Core\Injector\Injectable;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
use SilverStripe\Model\ArrayData;
|
||||
use SilverStripe\View\Requirements;
|
||||
use SilverStripe\View\SSViewer;
|
||||
@ -509,7 +510,7 @@ class Email extends SymfonyEmail
|
||||
// Plain render fallbacks to using the html render with html tags removed
|
||||
if (!$plainRender && $htmlRender) {
|
||||
// call html_entity_decode() to ensure any encoded HTML is also stripped inside ->Plain()
|
||||
$dbField = DBField::create_field('HTMLFragment', html_entity_decode($htmlRender));
|
||||
$dbField = DBFieldHelper::create_field('HTMLFragment', html_entity_decode($htmlRender));
|
||||
$plainRender = $dbField->Plain();
|
||||
}
|
||||
|
||||
|
@ -16,7 +16,7 @@ class CliBypass implements Bypass
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
Deprecation::withNoReplacement(function () {
|
||||
Deprecation::withSuppressedNotice(function () {
|
||||
Deprecation::notice(
|
||||
'5.4.0',
|
||||
'Will be removed without equivalent functionality to replace it',
|
||||
|
@ -4,6 +4,7 @@ namespace SilverStripe\Control\RSS;
|
||||
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
use SilverStripe\ORM\FieldType\DBHTMLText;
|
||||
use SilverStripe\Model\ModelData;
|
||||
use BadMethodCallException;
|
||||
|
@ -96,7 +96,7 @@ abstract class BuildTask
|
||||
*/
|
||||
public function getDescription()
|
||||
{
|
||||
Deprecation::withNoReplacement(
|
||||
Deprecation::withSuppressedNotice(
|
||||
fn() => Deprecation::notice('5.4.0', 'Will be replaced with a static method with the same name')
|
||||
);
|
||||
return $this->description;
|
||||
|
@ -53,7 +53,7 @@ class Deprecation
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
private static bool $insideWithNoReplacement = false;
|
||||
private static bool $insideNoticeSuppression = false;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
@ -103,22 +103,32 @@ class Deprecation
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to wrap deprecated methods and deprecated config get()/set() that will be removed
|
||||
* in the next major version with no replacement. This is done to surpress deprecation notices
|
||||
* by for calls from the vendor dir to deprecated code that projects have no ability to change
|
||||
* Used to wrap deprecated methods and deprecated config get()/set() called from the vendor
|
||||
* dir that projects have no ability to change.
|
||||
*
|
||||
* @return mixed
|
||||
* @deprecated 5.4.0 Use withSuppressedNotice() instead
|
||||
*/
|
||||
public static function withNoReplacement(callable $func)
|
||||
{
|
||||
if (Deprecation::$insideWithNoReplacement) {
|
||||
Deprecation::notice('5.4.0', 'Use withSuppressedNotice() instead');
|
||||
return Deprecation::withSuppressedNotice($func);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to wrap deprecated methods and deprecated config get()/set() called from the vendor
|
||||
* dir that projects have no ability to change.
|
||||
*/
|
||||
public static function withSuppressedNotice(callable $func): mixed
|
||||
{
|
||||
if (Deprecation::$insideNoticeSuppression) {
|
||||
return $func();
|
||||
}
|
||||
Deprecation::$insideWithNoReplacement = true;
|
||||
Deprecation::$insideNoticeSuppression = true;
|
||||
try {
|
||||
return $func();
|
||||
} finally {
|
||||
Deprecation::$insideWithNoReplacement = false;
|
||||
Deprecation::$insideNoticeSuppression = false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -137,8 +147,8 @@ class Deprecation
|
||||
$level = 1;
|
||||
}
|
||||
$newLevel = $level;
|
||||
// handle closures inside withNoReplacement()
|
||||
if (Deprecation::$insideWithNoReplacement
|
||||
// handle closures inside withSuppressedNotice()
|
||||
if (Deprecation::$insideNoticeSuppression
|
||||
&& substr($backtrace[$newLevel]['function'], -strlen('{closure}')) === '{closure}'
|
||||
) {
|
||||
$newLevel = $newLevel + 2;
|
||||
@ -247,8 +257,8 @@ class Deprecation
|
||||
$count++;
|
||||
$arr = array_shift(Deprecation::$userErrorMessageBuffer);
|
||||
$message = $arr['message'];
|
||||
$calledInsideWithNoReplacement = $arr['calledInsideWithNoReplacement'];
|
||||
if ($calledInsideWithNoReplacement && !Deprecation::$showNoReplacementNotices) {
|
||||
$calledWithNoticeSuppression = $arr['calledWithNoticeSuppression'];
|
||||
if ($calledWithNoticeSuppression && !Deprecation::$showNoReplacementNotices) {
|
||||
continue;
|
||||
}
|
||||
Deprecation::$isTriggeringError = true;
|
||||
@ -284,7 +294,7 @@ class Deprecation
|
||||
$data = [
|
||||
'key' => sha1($string),
|
||||
'message' => $string,
|
||||
'calledInsideWithNoReplacement' => Deprecation::$insideWithNoReplacement
|
||||
'calledWithNoticeSuppression' => Deprecation::$insideNoticeSuppression
|
||||
];
|
||||
} else {
|
||||
if (!Deprecation::isEnabled()) {
|
||||
@ -310,7 +320,7 @@ class Deprecation
|
||||
$string .= ".";
|
||||
}
|
||||
|
||||
$level = Deprecation::$insideWithNoReplacement ? 4 : 2;
|
||||
$level = Deprecation::$insideNoticeSuppression ? 4 : 2;
|
||||
$string .= " Called from " . Deprecation::get_called_method_from_trace($backtrace, $level) . '.';
|
||||
|
||||
if ($caller) {
|
||||
@ -319,7 +329,7 @@ class Deprecation
|
||||
$data = [
|
||||
'key' => sha1($string),
|
||||
'message' => $string,
|
||||
'calledInsideWithNoReplacement' => Deprecation::$insideWithNoReplacement
|
||||
'calledWithNoticeSuppression' => Deprecation::$insideNoticeSuppression
|
||||
];
|
||||
}
|
||||
if ($data && !array_key_exists($data['key'], Deprecation::$userErrorMessageBuffer)) {
|
||||
|
@ -34,7 +34,7 @@ class DevBuildController extends Controller implements PermissionProvider
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
Deprecation::withNoReplacement(function () {
|
||||
Deprecation::withSuppressedNotice(function () {
|
||||
Deprecation::notice(
|
||||
'5.4.0',
|
||||
'Will be replaced with SilverStripe\Dev\Command\DbBuild',
|
||||
|
@ -47,7 +47,7 @@ class DevConfigController extends Controller implements PermissionProvider
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
Deprecation::withNoReplacement(function () {
|
||||
Deprecation::withSuppressedNotice(function () {
|
||||
Deprecation::notice(
|
||||
'5.4.0',
|
||||
'Will be replaced with SilverStripe\Dev\Command\ConfigDump',
|
||||
|
@ -233,7 +233,7 @@ class DevelopmentAdmin extends Controller implements PermissionProvider
|
||||
*/
|
||||
public function buildDefaults()
|
||||
{
|
||||
Deprecation::withNoReplacement(function () {
|
||||
Deprecation::withSuppressedNotice(function () {
|
||||
Deprecation::notice(
|
||||
'5.4.0',
|
||||
'Will be replaced with SilverStripe\Dev\Command\DbDefaults'
|
||||
@ -266,7 +266,7 @@ class DevelopmentAdmin extends Controller implements PermissionProvider
|
||||
*/
|
||||
public function generatesecuretoken()
|
||||
{
|
||||
Deprecation::withNoReplacement(function () {
|
||||
Deprecation::withSuppressedNotice(function () {
|
||||
Deprecation::notice(
|
||||
'5.4.0',
|
||||
'Will be replaced with SilverStripe\Dev\Command\GenerateSecureToken'
|
||||
|
@ -36,7 +36,7 @@ class CleanupTestDatabasesTask extends BuildTask
|
||||
|
||||
public function canView(): bool
|
||||
{
|
||||
Deprecation::withNoReplacement(function () {
|
||||
Deprecation::withSuppressedNotice(function () {
|
||||
Deprecation::notice(
|
||||
'5.4.0',
|
||||
'Will be replaced with canRunInBrowser()'
|
||||
|
@ -6,6 +6,7 @@ use LogicException;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\DataObjectInterface;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
use SilverStripe\Security\Authenticator;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\View\HTML;
|
||||
@ -771,6 +772,6 @@ class ConfirmedPasswordField extends FormField
|
||||
if (strpos($attributes, 'required="required"') === false && $this->Required()) {
|
||||
$attributes .= ' required="required" aria-required="true"';
|
||||
}
|
||||
return DBField::create_field('HTMLFragment', $attributes);
|
||||
return DBFieldHelper::create_field('HTMLFragment', $attributes);
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,9 @@
|
||||
|
||||
namespace SilverStripe\Forms;
|
||||
|
||||
use SilverStripe\Core\Validation\ConstraintValidator;
|
||||
use Symfony\Component\Validator\Constraints;
|
||||
|
||||
/**
|
||||
* Text input field with validation for correct email format according to RFC 2822.
|
||||
*/
|
||||
@ -18,32 +21,27 @@ class EmailField extends TextField
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates for RFC 2822 compliant email addresses.
|
||||
*
|
||||
* @see http://www.regular-expressions.info/email.html
|
||||
* @see http://www.ietf.org/rfc/rfc2822.txt
|
||||
*
|
||||
* @param Validator $validator
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function validate($validator)
|
||||
{
|
||||
$result = true;
|
||||
$this->value = trim($this->value ?? '');
|
||||
|
||||
$pattern = '^[a-z0-9!#$%&\'*+/=?^_`{|}~-]+(?:\\.[a-z0-9!#$%&\'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$';
|
||||
$result = true;
|
||||
// $message = _t('SilverStripe\\Forms\\EmailField.VALIDATION', 'Please enter an email address');
|
||||
// $validationResult = ConstraintValidator::validate(
|
||||
// $this->value,
|
||||
// new Constraints\Email(message: $message)
|
||||
// );
|
||||
$validationResult = $this->getModelField()->validate();
|
||||
|
||||
// Escape delimiter characters.
|
||||
$safePattern = str_replace('/', '\\/', $pattern ?? '');
|
||||
|
||||
if ($this->value && !preg_match('/' . $safePattern . '/i', $this->value ?? '')) {
|
||||
if (!$validationResult->isValid()) {
|
||||
$validator->validationError(
|
||||
$this->name,
|
||||
_t('SilverStripe\\Forms\\EmailField.VALIDATION', 'Please enter an email address'),
|
||||
'validation'
|
||||
$validationResult->getMessages()[0]['message'],
|
||||
);
|
||||
|
||||
$result = false;
|
||||
}
|
||||
|
||||
|
@ -10,11 +10,16 @@ use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\ORM\DataObjectInterface;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
use SilverStripe\ORM\FieldType\DBHTMLText;
|
||||
use SilverStripe\Core\Validation\ValidationResult;
|
||||
use SilverStripe\View\AttributesHTML;
|
||||
use SilverStripe\View\SSViewer;
|
||||
use SilverStripe\Model\ModelData;
|
||||
use SilverStripe\Model\ModelFields\ModelField;
|
||||
use SilverStripe\Model\ModelFields\ModelFieldTrait;
|
||||
use SilverStripe\Model\ModelFields\StringModelField;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
|
||||
/**
|
||||
* Represents a field in a form.
|
||||
@ -40,11 +45,28 @@ use SilverStripe\Model\ModelData;
|
||||
* including both structure (name, id, attributes, etc.) and state (field value).
|
||||
* Can be used by for JSON data which is consumed by a front-end application.
|
||||
*/
|
||||
class FormField extends RequestHandler
|
||||
abstract class FormField extends RequestHandler
|
||||
{
|
||||
use AttributesHTML;
|
||||
use FormMessage;
|
||||
|
||||
// todo: possibly should make this abstract
|
||||
protected string $modelFieldClass = StringModelField::class;
|
||||
|
||||
private ModelField $modelField;
|
||||
|
||||
protected function getModelField(): ModelField
|
||||
{
|
||||
return $this->modelField;
|
||||
}
|
||||
|
||||
private function initModelField(): void
|
||||
{
|
||||
$name = $this->getName();
|
||||
$modelField = Injector::inst()->createWithArgs($this->modelFieldClass, [$name]);
|
||||
$this->modelField = $modelField;
|
||||
}
|
||||
|
||||
/** @see $schemaDataType */
|
||||
const SCHEMA_DATA_TYPE_STRING = 'String';
|
||||
|
||||
@ -344,6 +366,7 @@ class FormField extends RequestHandler
|
||||
|
||||
parent::__construct();
|
||||
|
||||
$this->initModelField($name);
|
||||
$this->setupDefaultClasses();
|
||||
}
|
||||
|
||||
@ -929,7 +952,7 @@ class FormField extends RequestHandler
|
||||
// Trim whitespace from the result, so that trailing newlines are suppressed. Works for strings and HTMLText values
|
||||
if (is_string($result)) {
|
||||
$result = trim($result ?? '');
|
||||
} elseif ($result instanceof DBField) {
|
||||
} elseif ($result instanceof ModelField) {
|
||||
$result->setValue(trim($result->getValue() ?? ''));
|
||||
}
|
||||
|
||||
@ -1231,9 +1254,12 @@ class FormField extends RequestHandler
|
||||
}
|
||||
|
||||
/**
|
||||
* Abstract method each {@link FormField} subclass must implement, determines whether the field
|
||||
* Method each {@link FormField} subclass can implement, determines whether the field
|
||||
* is valid or not based on the value.
|
||||
*
|
||||
* Subclass methods should call $this->extendValidationResult(true, $validator)
|
||||
* at the end of the method
|
||||
*
|
||||
* @param Validator $validator
|
||||
* @return bool
|
||||
*/
|
||||
|
@ -216,10 +216,10 @@ class FormRequestHandler extends RequestHandler
|
||||
// Action handlers may throw ValidationExceptions.
|
||||
try {
|
||||
// Or we can use the Validator attached to the form
|
||||
$result = $this->form->validationResult();
|
||||
if (!$result->isValid()) {
|
||||
return $this->getValidationErrorResponse($result);
|
||||
}
|
||||
// $result = $this->form->validationResult();
|
||||
// if (!$result->isValid()) {
|
||||
// return $this->getValidationErrorResponse($result);
|
||||
// }
|
||||
|
||||
// First, try a handler method on the controller (has been checked for allowed_actions above already)
|
||||
$controller = $this->form->getController();
|
||||
|
@ -22,6 +22,7 @@ use SilverStripe\Model\List\ArrayList;
|
||||
use SilverStripe\ORM\DataList;
|
||||
use SilverStripe\ORM\DataObjectInterface;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
use SilverStripe\Model\List\Filterable;
|
||||
use SilverStripe\Model\List\Limitable;
|
||||
use SilverStripe\Model\List\Sortable;
|
||||
@ -382,14 +383,14 @@ class GridField extends FormField
|
||||
|
||||
if (strpos($castingDefinition ?? '', '->') === false) {
|
||||
$castingFieldType = $castingDefinition;
|
||||
$castingField = DBField::create_field($castingFieldType, $value);
|
||||
$castingField = DBFieldHelper::create_field($castingFieldType, $value);
|
||||
|
||||
return call_user_func_array([$castingField, 'XML'], $castingParams ?? []);
|
||||
}
|
||||
|
||||
list($castingFieldType, $castingMethod) = explode('->', $castingDefinition ?? '');
|
||||
|
||||
$castingField = DBField::create_field($castingFieldType, $value);
|
||||
$castingField = DBFieldHelper::create_field($castingFieldType, $value);
|
||||
|
||||
return call_user_func_array([$castingField, $castingMethod], $castingParams ?? []);
|
||||
}
|
||||
@ -543,6 +544,8 @@ class GridField extends FormField
|
||||
'footer' => '',
|
||||
];
|
||||
|
||||
$_c = $this->getComponents();
|
||||
|
||||
foreach ($this->getComponents() as $item) {
|
||||
if ($item instanceof GridField_HTMLProvider) {
|
||||
$fragments = $item->getHTMLFragments($this);
|
||||
|
@ -25,7 +25,7 @@ class GridFieldConfig_Base extends GridFieldConfig
|
||||
$this->addComponent(GridFieldPageCount::create('toolbar-header-right'));
|
||||
$this->addComponent($pagination = GridFieldPaginator::create($itemsPerPage));
|
||||
|
||||
Deprecation::withNoReplacement(function () use ($sort, $filter, $pagination) {
|
||||
Deprecation::withSuppressedNotice(function () use ($sort, $filter, $pagination) {
|
||||
$sort->setThrowExceptionOnBadDataType(false);
|
||||
$filter->setThrowExceptionOnBadDataType(false);
|
||||
$pagination->setThrowExceptionOnBadDataType(false);
|
||||
|
@ -32,7 +32,7 @@ class GridFieldConfig_RecordEditor extends GridFieldConfig
|
||||
$this->addComponent($pagination = GridFieldPaginator::create($itemsPerPage));
|
||||
$this->addComponent(GridFieldDetailForm::create(null, $showPagination, $showAdd));
|
||||
|
||||
Deprecation::withNoReplacement(function () use ($sort, $filter, $pagination) {
|
||||
Deprecation::withSuppressedNotice(function () use ($sort, $filter, $pagination) {
|
||||
$sort->setThrowExceptionOnBadDataType(false);
|
||||
$filter->setThrowExceptionOnBadDataType(false);
|
||||
$pagination->setThrowExceptionOnBadDataType(false);
|
||||
|
@ -45,7 +45,7 @@ class GridFieldConfig_RelationEditor extends GridFieldConfig
|
||||
$this->addComponent($pagination = GridFieldPaginator::create($itemsPerPage));
|
||||
$this->addComponent(GridFieldDetailForm::create());
|
||||
|
||||
Deprecation::withNoReplacement(function () use ($sort, $filter, $pagination) {
|
||||
Deprecation::withSuppressedNotice(function () use ($sort, $filter, $pagination) {
|
||||
$sort->setThrowExceptionOnBadDataType(false);
|
||||
$filter->setThrowExceptionOnBadDataType(false);
|
||||
$pagination->setThrowExceptionOnBadDataType(false);
|
||||
|
@ -5,6 +5,7 @@ namespace SilverStripe\Forms\GridField;
|
||||
use LogicException;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
use SilverStripe\ORM\Hierarchy\Hierarchy;
|
||||
use SilverStripe\Model\ArrayData;
|
||||
use SilverStripe\View\HTML;
|
||||
@ -91,7 +92,7 @@ class GridFieldLevelup extends AbstractGridFieldComponent implements GridField_H
|
||||
$linkTag = HTML::createTag('a', $attrs);
|
||||
|
||||
$forTemplate = new ArrayData([
|
||||
'UpLink' => DBField::create_field('HTMLFragment', $linkTag)
|
||||
'UpLink' => DBFieldHelper::create_field('HTMLFragment', $linkTag)
|
||||
]);
|
||||
|
||||
$template = SSViewer::get_templates_by_class($this, '', __CLASS__);
|
||||
|
@ -6,6 +6,7 @@ use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Core\ArrayLib;
|
||||
use SilverStripe\ORM\DataObjectInterface;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
|
||||
/**
|
||||
* Read-only complement of {@link MultiSelectField}.
|
||||
@ -58,7 +59,7 @@ class LookupField extends MultiSelectField
|
||||
}
|
||||
|
||||
$properties = array_merge($properties, [
|
||||
'AttrValue' => DBField::create_field('HTMLFragment', $attrValue),
|
||||
'AttrValue' => DBFieldHelper::create_field('HTMLFragment', $attrValue),
|
||||
'InputValue' => $inputValue
|
||||
]);
|
||||
|
||||
|
@ -6,6 +6,7 @@ use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Core\ArrayLib;
|
||||
use SilverStripe\ORM\DataObjectInterface;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
use SilverStripe\Model\List\ArrayList;
|
||||
use SilverStripe\ORM\DataList;
|
||||
|
||||
|
@ -4,6 +4,7 @@ namespace SilverStripe\Forms;
|
||||
|
||||
use SilverStripe\Model\List\ArrayList;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
use SilverStripe\View\HTML;
|
||||
|
||||
/**
|
||||
@ -91,7 +92,7 @@ class SelectionGroup extends CompositeField
|
||||
|
||||
$itemID = $this->ID() . '_' . (++$count);
|
||||
$extra = [
|
||||
"RadioButton" => DBField::create_field('HTMLFragment', HTML::createTag(
|
||||
"RadioButton" => DBFieldHelper::create_field('HTMLFragment', HTML::createTag(
|
||||
'input',
|
||||
[
|
||||
'class' => 'selector',
|
||||
|
@ -6,6 +6,7 @@ use SilverStripe\Core\Convert;
|
||||
use SilverStripe\ORM\DataObjectInterface;
|
||||
use SilverStripe\Model\List\Map;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
|
||||
/**
|
||||
* Read-only complement of {@link DropdownField}.
|
||||
@ -125,7 +126,7 @@ class SingleLookupField extends SingleSelectField
|
||||
}
|
||||
|
||||
$properties = array_merge($properties, [
|
||||
'AttrValue' => DBField::create_field('HTMLFragment', $attrValue),
|
||||
'AttrValue' => DBFieldHelper::create_field('HTMLFragment', $attrValue),
|
||||
'InputValue' => $inputValue
|
||||
]);
|
||||
|
||||
|
@ -2,11 +2,15 @@
|
||||
|
||||
namespace SilverStripe\Forms;
|
||||
|
||||
use SilverStripe\Model\ModelFields\StringModelField;
|
||||
|
||||
/**
|
||||
* Text input field.
|
||||
*/
|
||||
class TextField extends FormField implements TippableFieldInterface
|
||||
{
|
||||
protected string $modelFieldClass = StringModelField::class;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
|
@ -4,6 +4,7 @@ namespace SilverStripe\Logging;
|
||||
|
||||
use Monolog\Formatter\FormatterInterface;
|
||||
use Monolog\Handler\AbstractProcessingHandler;
|
||||
use Monolog\Level;
|
||||
use Monolog\LogRecord;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\Director;
|
||||
@ -34,10 +35,10 @@ class HTTPOutputHandler extends AbstractProcessingHandler
|
||||
*/
|
||||
private $cliFormatter = null;
|
||||
|
||||
public function __construct()
|
||||
public function __construct(int|string|Level $level = Level::Debug, bool $bubble = true)
|
||||
{
|
||||
parent::__construct();
|
||||
Deprecation::withNoReplacement(function () {
|
||||
parent::__construct($level, $bubble);
|
||||
Deprecation::withSuppressedNotice(function () {
|
||||
Deprecation::notice(
|
||||
'5.4.0',
|
||||
'Will be renamed to ErrorOutputHandler',
|
||||
|
@ -720,7 +720,7 @@ class ArrayList extends ModelData implements SS_List, Filterable, Sortable, Limi
|
||||
|
||||
// Apply default case sensitivity for backwards compatability
|
||||
if (!str_contains($filterKey, ':case') && !str_contains($filterKey, ':nocase')) {
|
||||
$caseSensitive = Deprecation::withNoReplacement(fn() => static::config()->get('default_case_sensitive'));
|
||||
$caseSensitive = Deprecation::withSuppressedNotice(fn() => static::config()->get('default_case_sensitive'));
|
||||
if ($caseSensitive && in_array('case', $searchFilter->getSupportedModifiers())) {
|
||||
$searchFilter->setModifiers($searchFilter->getModifiers() + ['case']);
|
||||
} elseif (!$caseSensitive && in_array('nocase', $searchFilter->getSupportedModifiers())) {
|
||||
|
@ -16,11 +16,12 @@ use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Dev\Debug;
|
||||
use SilverStripe\Core\ArrayLib;
|
||||
use SilverStripe\Model\List\ArrayList;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBHTMLText;
|
||||
use SilverStripe\Model\ArrayData;
|
||||
use SilverStripe\View\SSViewer;
|
||||
use UnexpectedValueException;
|
||||
use SilverStripe\Model\ModelField;
|
||||
use SilverStripe\Core\Validation\ValidationResult;
|
||||
|
||||
/**
|
||||
* A ModelData object is any object that can be rendered into a template/view.
|
||||
@ -327,7 +328,7 @@ class ModelData
|
||||
|
||||
/**
|
||||
* Return the "casting helper" (a piece of PHP code that when evaluated creates a casted value object)
|
||||
* for a field on this object. This helper will be a subclass of DBField.
|
||||
* for a field on this object. This helper will be a subclass of ModelField.
|
||||
*
|
||||
* @param bool $useFallback If true, fall back on the default casting helper if there isn't an explicit one.
|
||||
* @return string|null Casting helper As a constructor pattern, and may include arguments.
|
||||
@ -361,7 +362,7 @@ class ModelData
|
||||
|
||||
/**
|
||||
* Return the default "casting helper" for use when no explicit casting helper is defined.
|
||||
* This helper will be a subclass of DBField. See castingHelper()
|
||||
* This helper will be a subclass of ModelField. See castingHelper()
|
||||
*/
|
||||
protected function defaultCastingHelper(string $field): string
|
||||
{
|
||||
@ -402,7 +403,7 @@ class ModelData
|
||||
{
|
||||
$class = $this->castingClass($field) ?: $this->config()->get('default_cast');
|
||||
|
||||
/** @var DBField $type */
|
||||
/** @var ModelField $type */
|
||||
$type = Injector::inst()->get($class, true);
|
||||
return $type->config()->get('escape_type');
|
||||
}
|
||||
@ -495,9 +496,9 @@ class ModelData
|
||||
* Get the value of a field on this object, automatically inserting the value into any available casting objects
|
||||
* that have been specified.
|
||||
*
|
||||
* @return object|DBField|null The specific object representing the field, or null if there is no
|
||||
* @return object|ModelField|null The specific object representing the field, or null if there is no
|
||||
* property, method, or dynamic data available for that field.
|
||||
* Note that if there is a property or method that returns null, a relevant DBField instance will
|
||||
* Note that if there is a property or method that returns null, a relevant ModelField instance will
|
||||
* be returned.
|
||||
*/
|
||||
public function obj(
|
||||
@ -520,7 +521,13 @@ class ModelData
|
||||
// Load value from record
|
||||
if ($this->hasMethod($fieldName)) {
|
||||
$hasObj = true;
|
||||
$value = call_user_func_array([$this, $fieldName], $arguments ?: []);
|
||||
// todo: remove try catch block
|
||||
try {
|
||||
$value = call_user_func_array([$this, $fieldName], $arguments ?: []);
|
||||
} catch (Exception $e) {
|
||||
$x=1;
|
||||
throw $e;
|
||||
}
|
||||
} else {
|
||||
$hasObj = $this->hasField($fieldName) || ($this->hasMethod("get{$fieldName}") && $this->isAccessibleMethod("get{$fieldName}"));
|
||||
$value = $this->$fieldName;
|
||||
@ -568,7 +575,7 @@ class ModelData
|
||||
* A simple wrapper around {@link ModelData::obj()} that automatically caches the result so it can be used again
|
||||
* without re-running the method.
|
||||
*
|
||||
* @return Object|DBField
|
||||
* @return Object|ModelField
|
||||
*/
|
||||
public function cachedCall(string $fieldName, array $arguments = [], ?string $cacheName = null): object
|
||||
{
|
||||
@ -599,7 +606,13 @@ class ModelData
|
||||
return '';
|
||||
}
|
||||
// Might contain additional formatting over ->XML(). E.g. parse shortcodes, nl2br()
|
||||
return $result->forTemplate();
|
||||
// todo: remove try catch block
|
||||
try {
|
||||
return $result->forTemplate();
|
||||
} catch (Exception $e) {
|
||||
$x=1;
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
25
src/Model/ModelFields/EmailModelField.php
Normal file
25
src/Model/ModelFields/EmailModelField.php
Normal file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\Model\ModelFields;
|
||||
|
||||
use SilverStripe\Core\Validation\ValidationResult;
|
||||
use SilverStripe\Model\ModelFields\StringModelField;
|
||||
use SilverStripe\Core\Validation\ConstraintValidator;
|
||||
use Symfony\Component\Validator\Constraints;
|
||||
|
||||
class EmailModelField extends StringModelField
|
||||
{
|
||||
public function validate(): ValidationResult
|
||||
{
|
||||
$result = parent::validate();
|
||||
$message = _t('SilverStripe\\Forms\\EmailField.VALIDATION', 'Please enter an email address');
|
||||
|
||||
$validationResult = ConstraintValidator::validate(
|
||||
$this->getValue(),
|
||||
new Constraints\Email(message: $message),
|
||||
$this->getName()
|
||||
);
|
||||
|
||||
return $result->combineAnd($validationResult);
|
||||
}
|
||||
}
|
249
src/Model/ModelFields/ModelField.php
Normal file
249
src/Model/ModelFields/ModelField.php
Normal file
@ -0,0 +1,249 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\Model\ModelFields;
|
||||
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\Forms\TextField;
|
||||
use SilverStripe\Model\ModelData;
|
||||
use SilverStripe\Core\Validation\ValidationResult;
|
||||
|
||||
abstract class ModelField extends ModelData
|
||||
{
|
||||
/**
|
||||
* Raw value of this field
|
||||
*/
|
||||
protected mixed $value = null;
|
||||
|
||||
/**
|
||||
* Name of this field
|
||||
*/
|
||||
protected ?string $name = null;
|
||||
|
||||
/**
|
||||
* The escape type for this field when inserted into a template - either "xml" or "raw".
|
||||
*/
|
||||
private static string $escape_type = 'raw';
|
||||
|
||||
private static array $casting = [
|
||||
'ATT' => 'HTMLFragment',
|
||||
'CDATA' => 'HTMLFragment',
|
||||
'HTML' => 'HTMLFragment',
|
||||
'HTMLATT' => 'HTMLFragment',
|
||||
'JS' => 'HTMLFragment',
|
||||
'RAW' => 'HTMLFragment',
|
||||
'RAWURLATT' => 'HTMLFragment',
|
||||
'URLATT' => 'HTMLFragment',
|
||||
'XML' => 'HTMLFragment',
|
||||
'ProcessedRAW' => 'HTMLFragment',
|
||||
];
|
||||
|
||||
public function __construct(?string $name = null)
|
||||
{
|
||||
$this->name = $name;
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function setName(?string $name): static
|
||||
{
|
||||
$this->name = $name;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this field.
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this field.
|
||||
*/
|
||||
public function getValue(): mixed
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
public function setValue(mixed $value): static
|
||||
{
|
||||
$this->value = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine 'default' casting for this field.
|
||||
*/
|
||||
public function forTemplate(): string
|
||||
{
|
||||
// Default to XML encoding
|
||||
return $this->XML();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value appropriate for a HTML attribute string
|
||||
*/
|
||||
public function HTMLATT(): string
|
||||
{
|
||||
return Convert::raw2htmlatt($this->RAW());
|
||||
}
|
||||
|
||||
/**
|
||||
* urlencode this string
|
||||
*/
|
||||
public function URLATT(): string
|
||||
{
|
||||
return urlencode($this->RAW() ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* rawurlencode this string
|
||||
*/
|
||||
public function RAWURLATT(): string
|
||||
{
|
||||
return rawurlencode($this->RAW() ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value appropriate for a HTML attribute string
|
||||
*/
|
||||
public function ATT(): string
|
||||
{
|
||||
return Convert::raw2att($this->RAW());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the raw value for this field.
|
||||
* Note: Skips processors implemented via forTemplate()
|
||||
*/
|
||||
public function RAW(): mixed
|
||||
{
|
||||
return $this->getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets javascript string literal value
|
||||
*/
|
||||
public function JS(): string
|
||||
{
|
||||
return Convert::raw2js($this->RAW());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return JSON encoded value
|
||||
*/
|
||||
public function JSON(): string
|
||||
{
|
||||
return json_encode($this->RAW());
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for {@see XML()}
|
||||
*/
|
||||
public function HTML(): string
|
||||
{
|
||||
return $this->XML();
|
||||
}
|
||||
|
||||
/**
|
||||
* XML encode this value
|
||||
*/
|
||||
public function XML(): string
|
||||
{
|
||||
return Convert::raw2xml($this->RAW());
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely escape for XML string
|
||||
*/
|
||||
public function CDATA(): string
|
||||
{
|
||||
return $this->XML();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves this field to the given data object.
|
||||
*
|
||||
* TODO: probably rename, it's just setting a field on a model
|
||||
*/
|
||||
public function saveInto(ModelData $model): void
|
||||
{
|
||||
$fieldName = $this->name;
|
||||
if (empty($fieldName)) {
|
||||
throw new \BadMethodCallException(
|
||||
"ModelField::saveInto() Called on a nameless '" . static::class . "' object"
|
||||
);
|
||||
}
|
||||
if ($this->value instanceof ModelField) {
|
||||
$this->value->saveInto($model);
|
||||
} else {
|
||||
$model->__set($fieldName, $this->value);
|
||||
}
|
||||
}
|
||||
|
||||
public function validate(): ValidationResult
|
||||
{
|
||||
return ValidationResult::create();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a FormField instance used as a default
|
||||
* for form scaffolding.
|
||||
*
|
||||
* Used by {@link SearchContext}, {@link ModelAdmin}, {@link DataObject::scaffoldFormFields()}
|
||||
*
|
||||
* @param string $title Optional. Localized title of the generated instance
|
||||
*/
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
return TextField::create($this->name, $title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a FormField instance used as a default
|
||||
* for searchform scaffolding.
|
||||
*
|
||||
* Used by {@link SearchContext}, {@link ModelAdmin}, {@link DataObject::scaffoldFormFields()}.
|
||||
*
|
||||
* @param string $title Optional. Localized title of the generated instance
|
||||
*/
|
||||
public function scaffoldSearchField(?string $title = null): ?FormField
|
||||
{
|
||||
return $this->scaffoldFormField($title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get formfield schema value for use in formschema response
|
||||
*/
|
||||
public function getSchemaValue(): mixed
|
||||
{
|
||||
return $this->RAW();
|
||||
}
|
||||
|
||||
public function debug(): string
|
||||
{
|
||||
return <<<DBG
|
||||
<ul>
|
||||
<li><b>Name:</b>{$this->name}</li>
|
||||
<li><b>Table:</b>{$this->tableName}</li>
|
||||
<li><b>Value:</b>{$this->value}</li>
|
||||
</ul>
|
||||
DBG;
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string)$this->forTemplate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether or not this ModelField only accepts scalar values.
|
||||
*
|
||||
* Composite ModelFields can override this method and return `false` so they can accept arrays of values.
|
||||
*/
|
||||
public function scalarValueOnly(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
142
src/Model/ModelFields/StringModelField.php
Normal file
142
src/Model/ModelFields/StringModelField.php
Normal file
@ -0,0 +1,142 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\Model\ModelFields;
|
||||
|
||||
use SilverStripe\Model\ModelFields\ModelField;
|
||||
use SilverStripe\ORM\FieldType\DBString;
|
||||
|
||||
class StringModelField extends ModelField
|
||||
{
|
||||
private static array $casting = [
|
||||
'LimitCharacters' => 'Text',
|
||||
'LimitCharactersToClosestWord' => 'Text',
|
||||
'LimitWordCount' => 'Text',
|
||||
'LowerCase' => 'Text',
|
||||
'UpperCase' => 'Text',
|
||||
'Plain' => 'Text',
|
||||
];
|
||||
|
||||
public function forTemplate(): string
|
||||
{
|
||||
return nl2br(parent::forTemplate() ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Limit this field's content by a number of characters.
|
||||
* This makes use of strip_tags() to avoid malforming the
|
||||
* HTML tags in the string of text.
|
||||
*
|
||||
* @param int $limit Number of characters to limit by
|
||||
* @param string|false $add Ellipsis to add to the end of truncated string
|
||||
*/
|
||||
public function LimitCharacters(int $limit = 20, string|false $add = false): string
|
||||
{
|
||||
$value = $this->Plain();
|
||||
if (mb_strlen($value ?? '') <= $limit) {
|
||||
return $value;
|
||||
}
|
||||
return $this->addEllipsis(mb_substr($value ?? '', 0, $limit), $add);
|
||||
}
|
||||
|
||||
/**
|
||||
* Limit this field's content by a number of characters and truncate
|
||||
* the field to the closest complete word. All HTML tags are stripped
|
||||
* from the field.
|
||||
*
|
||||
* @param int $limit Number of characters to limit by
|
||||
* @param string|false $add Ellipsis to add to the end of truncated string
|
||||
* @return string Plain text value with limited characters
|
||||
*/
|
||||
public function LimitCharactersToClosestWord(int $limit = 20, string|false $add = false): string
|
||||
{
|
||||
// Safely convert to plain text
|
||||
$value = $this->Plain();
|
||||
|
||||
// Determine if value exceeds limit before limiting characters
|
||||
if (mb_strlen($value ?? '') <= $limit) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Limit to character limit
|
||||
$value = mb_substr($value ?? '', 0, $limit);
|
||||
|
||||
// If value exceeds limit, strip punctuation off the end to the last space and apply ellipsis
|
||||
$value = $this->addEllipsis(
|
||||
preg_replace(
|
||||
'/[^\w_]+$/',
|
||||
'',
|
||||
mb_substr($value ?? '', 0, mb_strrpos($value ?? '', " "))
|
||||
),
|
||||
$add
|
||||
);
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Limit this field's content by a number of words.
|
||||
*
|
||||
* @param int $numWords Number of words to limit by.
|
||||
* @param string|false $add Ellipsis to add to the end of truncated string.
|
||||
*/
|
||||
public function LimitWordCount(int $numWords = 26, string|false $add = false): string
|
||||
{
|
||||
$value = $this->Plain();
|
||||
$words = explode(' ', $value ?? '');
|
||||
if (count($words ?? []) <= $numWords) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Limit
|
||||
$words = array_slice($words ?? [], 0, $numWords);
|
||||
return $this->addEllipsis(implode(' ', $words), $add);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the current value for this StringField to lowercase.
|
||||
*
|
||||
* @return string Text with lowercase (HTML for some subclasses)
|
||||
*/
|
||||
public function LowerCase(): string
|
||||
{
|
||||
return mb_strtolower($this->RAW() ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the current value for this StringField to uppercase.
|
||||
*
|
||||
* @return string Text with uppercase (HTML for some subclasses)
|
||||
*/
|
||||
public function UpperCase(): string
|
||||
{
|
||||
return mb_strtoupper($this->RAW() ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Plain text version of this string
|
||||
*/
|
||||
public function Plain(): string
|
||||
{
|
||||
return trim($this->RAW() ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Swap add for defaultEllipsis if need be
|
||||
*/
|
||||
private function addEllipsis(string $string, string|false $add): string
|
||||
{
|
||||
if ($add === false) {
|
||||
$add = $this->defaultEllipsis();
|
||||
}
|
||||
|
||||
return $string . $add;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default string to indicate that a string was cut off.
|
||||
*/
|
||||
public function defaultEllipsis(): string
|
||||
{
|
||||
// TODO: Change to translation key defined on StringModelField
|
||||
return _t(DBString::class . '.ELLIPSIS', '…');
|
||||
}
|
||||
}
|
@ -10,6 +10,7 @@ use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
use SilverStripe\ORM\FieldType\DBPrimaryKey;
|
||||
|
||||
/**
|
||||
|
@ -6,6 +6,7 @@ use mysqli;
|
||||
use mysqli_sql_exception;
|
||||
use mysqli_stmt;
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Core\Environment;
|
||||
|
||||
/**
|
||||
* Connector for MySQL using the MySQLi method
|
||||
@ -81,15 +82,21 @@ class MySQLiConnector extends DBConnector
|
||||
// Connection charset and collation
|
||||
$connCharset = Config::inst()->get(MySQLDatabase::class, 'connection_charset');
|
||||
$connCollation = Config::inst()->get(MySQLDatabase::class, 'connection_collation');
|
||||
$socket = Environment::getEnv('SS_DATABASE_SOCKET');
|
||||
$flags = Environment::getEnv('SS_DATABASE_FLAGS');
|
||||
|
||||
$flags = $flags ? array_reduce(explode(',', $flags), function ($carry, $item) {
|
||||
$item = trim($item);
|
||||
return $carry | constant($item);
|
||||
}, 0) : $flags;
|
||||
|
||||
$this->dbConn = mysqli_init();
|
||||
|
||||
// Use native types (MysqlND only)
|
||||
if (defined('MYSQLI_OPT_INT_AND_FLOAT_NATIVE')) {
|
||||
$this->dbConn->options(MYSQLI_OPT_INT_AND_FLOAT_NATIVE, true);
|
||||
|
||||
// The alternative is not ideal, throw a notice-level error
|
||||
} else {
|
||||
// The alternative is not ideal, throw a notice-level error
|
||||
user_error(
|
||||
'mysqlnd PHP library is not available, numeric values will be fetched from the DB as strings',
|
||||
E_USER_NOTICE
|
||||
@ -117,7 +124,9 @@ class MySQLiConnector extends DBConnector
|
||||
$parameters['username'],
|
||||
$parameters['password'],
|
||||
$selectedDB,
|
||||
!empty($parameters['port']) ? $parameters['port'] : ini_get("mysqli.default_port")
|
||||
!empty($parameters['port']) ? $parameters['port'] : ini_get("mysqli.default_port"),
|
||||
$socket ?? null,
|
||||
$flags ?? 0
|
||||
);
|
||||
|
||||
if ($this->dbConn->connect_error) {
|
||||
@ -126,8 +135,8 @@ class MySQLiConnector extends DBConnector
|
||||
|
||||
// Set charset and collation if given and not null. Can explicitly set to empty string to omit
|
||||
$charset = isset($parameters['charset'])
|
||||
? $parameters['charset']
|
||||
: $connCharset;
|
||||
? $parameters['charset']
|
||||
: $connCharset;
|
||||
|
||||
if (!empty($charset)) {
|
||||
$this->dbConn->set_charset($charset);
|
||||
|
@ -20,6 +20,7 @@ use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\Forms\FormScaffolder;
|
||||
use SilverStripe\Forms\CompositeValidator;
|
||||
use SilverStripe\Forms\FieldsValidator;
|
||||
use SilverStripe\Forms\Form;
|
||||
use SilverStripe\Forms\GridField\GridField;
|
||||
use SilverStripe\Forms\GridField\GridFieldConfig_RelationEditor;
|
||||
use SilverStripe\Forms\HiddenField;
|
||||
@ -33,6 +34,7 @@ use SilverStripe\ORM\FieldType\DBComposite;
|
||||
use SilverStripe\ORM\FieldType\DBDatetime;
|
||||
use SilverStripe\ORM\FieldType\DBEnum;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
use SilverStripe\ORM\FieldType\DBForeignKey;
|
||||
use SilverStripe\ORM\Filters\PartialMatchFilter;
|
||||
use SilverStripe\ORM\Filters\SearchFilter;
|
||||
@ -45,7 +47,13 @@ use SilverStripe\Security\Permission;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\View\SSViewer;
|
||||
use SilverStripe\Model\ModelData;
|
||||
use SilverStripe\ORM\FieldType\DBText;
|
||||
use SilverStripe\ORM\FieldType\DBVarchar;
|
||||
use stdClass;
|
||||
use SilverStripe\Control\Controller;
|
||||
use SilverStripe\Control\HTTPRequest;
|
||||
use SilverStripe\Control\Session;
|
||||
use Symfony\Component\Validator\Constraints\Uuid;
|
||||
|
||||
/**
|
||||
* A single database record & abstract class for the data-access-model.
|
||||
@ -1230,10 +1238,44 @@ class DataObject extends ModelData implements DataObjectInterface, i18nEntityPro
|
||||
public function validate()
|
||||
{
|
||||
$result = ValidationResult::create();
|
||||
// Call validate() on every DBField
|
||||
$specs = static::getSchema()->fieldSpecs(static::class);
|
||||
foreach (array_keys($specs) as $fieldName) {
|
||||
// Call DBField::validate() on every DBField
|
||||
$dbField = $this->dbObject($fieldName);
|
||||
$result->combineAnd($dbField->validate());
|
||||
}
|
||||
// If it passed DBField::validate(), then call FormField::validate()
|
||||
// on every field that would be scaffolded
|
||||
// This isn't ideal and can lead to double validation, however it's to preserve
|
||||
// any legacy FormField::validate() logic on projects that has not been
|
||||
// migrated to use DBField::validate()
|
||||
// TODO: don't call this when in FormRequestHandler::httpSubmission()
|
||||
// as it means that calling FormField::validate() is called twice
|
||||
if ($result->isValid()) {
|
||||
$form = $this->getFormForValidation();
|
||||
$result->combineAnd($form->validationResult());
|
||||
}
|
||||
// Call extension hook and return
|
||||
$this->extend('updateValidate', $result);
|
||||
return $result;
|
||||
}
|
||||
|
||||
private function getFormForValidation(): Form
|
||||
{
|
||||
$session = new Session([]);
|
||||
$controller = new Controller();
|
||||
$request = new HTTPRequest('GET', '/');
|
||||
$request->setSession($session);
|
||||
$controller->setRequest($request);
|
||||
// Use getCMSFields rather than $dbField->scaffoldFormField()
|
||||
// to ensure we get any CMS fields that were replaced by other fields
|
||||
$fields = $this->getCMSFields();
|
||||
$form = new Form($controller, sprintf('temp-%s', uniqid()), $fields, null, new FieldsValidator);
|
||||
$form->loadDataFrom($this);
|
||||
return $form;
|
||||
}
|
||||
|
||||
/**
|
||||
* Event handler called before writing to the database.
|
||||
* You can overload this to clean up or otherwise process data before writing it to the
|
||||
@ -1456,7 +1498,7 @@ class DataObject extends ModelData implements DataObjectInterface, i18nEntityPro
|
||||
// if database column doesn't correlate to a DBField instance...
|
||||
$fieldObj = $this->dbObject($fieldName);
|
||||
if (!$fieldObj) {
|
||||
$fieldObj = DBField::create_field('Varchar', $fieldValue, $fieldName);
|
||||
$fieldObj = DBFieldHelper::create_field('Varchar', $fieldValue, $fieldName);
|
||||
}
|
||||
|
||||
// Write to manipulation
|
||||
@ -1982,7 +2024,7 @@ class DataObject extends ModelData implements DataObjectInterface, i18nEntityPro
|
||||
if ($details['polymorphic']) {
|
||||
$result = PolymorphicHasManyList::create($componentClass, $details['joinField'], static::class);
|
||||
if ($details['needsRelation']) {
|
||||
Deprecation::withNoReplacement(fn () => $result->setForeignRelation($componentName));
|
||||
Deprecation::withSuppressedNotice(fn () => $result->setForeignRelation($componentName));
|
||||
}
|
||||
} else {
|
||||
$result = HasManyList::create($componentClass, $details['joinField']);
|
||||
@ -2422,16 +2464,15 @@ class DataObject extends ModelData implements DataObjectInterface, i18nEntityPro
|
||||
}
|
||||
|
||||
// Otherwise, use the database field's scaffolder
|
||||
} elseif ($object = $this->relObject($fieldName)) {
|
||||
if (is_object($object) && $object->hasMethod('scaffoldSearchField')) {
|
||||
$field = $object->scaffoldSearchField();
|
||||
} else {
|
||||
} elseif ($dbField = $this->relObject($fieldName)) {
|
||||
if (!is_a($dbField, DBField::class)) {
|
||||
throw new Exception(sprintf(
|
||||
"SearchField '%s' on '%s' does not return a valid DBField instance.",
|
||||
$fieldName,
|
||||
get_class($this)
|
||||
));
|
||||
}
|
||||
$field = $dbField->scaffoldSearchField();
|
||||
}
|
||||
|
||||
// Allow fields to opt out of search
|
||||
|
@ -16,6 +16,7 @@ use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\Connect\DBSchemaManager;
|
||||
use SilverStripe\ORM\FieldType\DBComposite;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
|
||||
/**
|
||||
* Provides dataobject and database schema mapping functionality
|
||||
|
@ -67,7 +67,7 @@ class DatabaseAdmin extends Controller
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
Deprecation::withNoReplacement(function () {
|
||||
Deprecation::withSuppressedNotice(function () {
|
||||
Deprecation::notice(
|
||||
'5.4.0',
|
||||
'Will be replaced with SilverStripe\Dev\Command\DbBuild',
|
||||
@ -213,7 +213,7 @@ class DatabaseAdmin extends Controller
|
||||
*/
|
||||
public static function lastBuilt()
|
||||
{
|
||||
Deprecation::withNoReplacement(function () {
|
||||
Deprecation::withSuppressedNotice(function () {
|
||||
Deprecation::notice(
|
||||
'5.4.0',
|
||||
'Will be replaced with SilverStripe\Dev\Command\DbBuild::lastBuilt()'
|
||||
|
@ -6,6 +6,7 @@ use SilverStripe\Dev\Debug;
|
||||
use SilverStripe\Model\ModelData;
|
||||
use SilverStripe\ORM\Connect\DatabaseException;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
use BadMethodCallException;
|
||||
use InvalidArgumentException;
|
||||
use LogicException;
|
||||
|
@ -7,12 +7,17 @@ use SilverStripe\Forms\DropdownField;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\Model\ModelData;
|
||||
use SilverStripe\Model\ModelFields\ModelField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldTrait;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
|
||||
/**
|
||||
* Represents a boolean field.
|
||||
*/
|
||||
class DBBoolean extends DBField
|
||||
class DBBoolean extends ModelField implements DBField
|
||||
{
|
||||
use DBFieldTrait;
|
||||
|
||||
public function __construct(?string $name = null, bool|int $defaultVal = 0)
|
||||
{
|
||||
$this->defaultVal = ($defaultVal) ? 1 : 0;
|
||||
|
@ -8,6 +8,9 @@ use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\Queries\SQLSelect;
|
||||
use SilverStripe\Model\ModelData;
|
||||
use SilverStripe\Model\ModelFields\ModelField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldTrait;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
|
||||
/**
|
||||
* Extend this class when designing a {@link DBField} that doesn't have a 1-1 mapping with a database field.
|
||||
@ -23,8 +26,10 @@ use SilverStripe\Model\ModelData;
|
||||
* }
|
||||
* </code>
|
||||
*/
|
||||
abstract class DBComposite extends DBField
|
||||
abstract class DBComposite extends ModelField implements DBField
|
||||
{
|
||||
use DBFieldTrait;
|
||||
|
||||
/**
|
||||
* Similar to {@link DataObject::$db},
|
||||
* holds an array of composite field names.
|
||||
@ -85,8 +90,6 @@ abstract class DBComposite extends DBField
|
||||
*/
|
||||
public function addToQuery(SQLSelect &$query): void
|
||||
{
|
||||
parent::addToQuery($query);
|
||||
|
||||
foreach ($this->compositeDatabaseFields() as $field => $spec) {
|
||||
$table = $this->getTable();
|
||||
$key = $this->getName() . $field;
|
||||
|
@ -12,6 +12,9 @@ use SilverStripe\ORM\DB;
|
||||
use SilverStripe\Security\Member;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\Model\ModelData;
|
||||
use SilverStripe\ORM\FieldType\DBFieldTrait;
|
||||
use SilverStripe\Model\ModelFields\ModelField;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
|
||||
/**
|
||||
* Represents a date field.
|
||||
@ -29,8 +32,10 @@ use SilverStripe\Model\ModelData;
|
||||
* Date formats all follow CLDR standard format codes
|
||||
* @link https://unicode-org.github.io/icu/userguide/format_parse/datetime
|
||||
*/
|
||||
class DBDate extends DBField
|
||||
class DBDate extends ModelField implements DBField
|
||||
{
|
||||
use DBFieldTrait;
|
||||
|
||||
/**
|
||||
* Standard ISO format string for date in CLDR standard format
|
||||
*/
|
||||
|
@ -260,7 +260,7 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
|
||||
$time = DBDatetime::$mock_now ? DBDatetime::$mock_now->Value : time();
|
||||
|
||||
/** @var DBDatetime $now */
|
||||
$now = DBField::create_field('Datetime', $time);
|
||||
$now = DBFieldHelper::create_field('Datetime', $time);
|
||||
|
||||
return $now;
|
||||
}
|
||||
@ -277,7 +277,7 @@ class DBDatetime extends DBDate implements TemplateGlobalProvider
|
||||
{
|
||||
if (!$datetime instanceof DBDatetime) {
|
||||
$value = $datetime;
|
||||
$datetime = DBField::create_field('Datetime', $datetime);
|
||||
$datetime = DBFieldHelper::create_field('Datetime', $datetime);
|
||||
if ($datetime === false) {
|
||||
throw new InvalidArgumentException('DBDatetime::set_mock_now(): Wrong format: ' . $value);
|
||||
}
|
||||
|
@ -6,12 +6,16 @@ use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\Forms\NumericField;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\Model\ModelData;
|
||||
use SilverStripe\ORM\FieldType\DBFieldTrait;
|
||||
use SilverStripe\Model\ModelFields\ModelField;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
|
||||
/**
|
||||
* Represents a Decimal field.
|
||||
*/
|
||||
class DBDecimal extends DBField
|
||||
class DBDecimal extends ModelField implements DBField
|
||||
{
|
||||
use DBFieldTrait;
|
||||
/**
|
||||
* Whole number size
|
||||
*/
|
||||
|
44
src/ORM/FieldType/DBEmail.php
Normal file
44
src/ORM/FieldType/DBEmail.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use SilverStripe\ORM\FieldType\DBVarchar;
|
||||
use Symfony\Component\Validator\Constraints;
|
||||
use SilverStripe\Core\Validation\ConstraintValidator;
|
||||
use SilverStripe\Core\Validation\ValidationResult;
|
||||
use SilverStripe\Forms\EmailField;
|
||||
use SilverStripe\Forms\NullableField;
|
||||
use SilverStripe\Forms\FormField;
|
||||
|
||||
class DBEmail extends DBVarchar
|
||||
{
|
||||
// public function validate(): ValidationResult
|
||||
// {
|
||||
// // https://symfony.com/doc/current/reference/constraints/Email.html
|
||||
// $result = parent::validate();
|
||||
// // $message = _t('SilverStripe\\Forms\\EmailField.VALIDATION', 'Please enter an email address');
|
||||
// // $result = $result->combineAnd(
|
||||
// // ConstraintValidator::validate(
|
||||
// // $this->getValue(),
|
||||
// // new Constraints\Email(message: $message),
|
||||
// // $this->getName()
|
||||
// // )
|
||||
// // );
|
||||
// $result = $result->combineAnd($this->validateEmail());
|
||||
// $this->extend('updateValidate', $result);
|
||||
// return $result;
|
||||
// }
|
||||
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
// Set field with appropriate size
|
||||
$field = EmailField::create($this->name, $title);
|
||||
$field->setMaxLength($this->getSize());
|
||||
|
||||
// Allow the user to select if it's null instead of automatically assuming empty string is
|
||||
if (!$this->getNullifyEmpty()) {
|
||||
return NullableField::create($field);
|
||||
}
|
||||
return $field;
|
||||
}
|
||||
}
|
@ -2,567 +2,9 @@
|
||||
|
||||
namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\Forms\TextField;
|
||||
use SilverStripe\ORM\Filters\SearchFilter;
|
||||
use SilverStripe\ORM\Queries\SQLSelect;
|
||||
use SilverStripe\Model\ModelData;
|
||||
|
||||
/**
|
||||
* Single field in the database.
|
||||
*
|
||||
* Every field from the database is represented as a sub-class of DBField.
|
||||
*
|
||||
* <b>Multi-value DBField objects</b>
|
||||
*
|
||||
* Sometimes you will want to make DBField classes that don't have a 1-1 match
|
||||
* to database fields. To do this, there are a number of fields for you to
|
||||
* overload:
|
||||
*
|
||||
* - Overload {@link writeToManipulation} to add the appropriate references to
|
||||
* the INSERT or UPDATE command
|
||||
* - Overload {@link addToQuery} to add the appropriate items to a SELECT
|
||||
* query's field list
|
||||
* - Add appropriate accessor methods
|
||||
*
|
||||
* <b>Subclass Example</b>
|
||||
*
|
||||
* The class is easy to overload with custom types, e.g. the MySQL "BLOB" type
|
||||
* (https://dev.mysql.com/doc/refman/8.4/en/blob.html).
|
||||
*
|
||||
* <code>
|
||||
* class Blob extends DBField {
|
||||
* function requireField(): void {
|
||||
* DB::require_field($this->tableName, $this->name, "blob");
|
||||
* }
|
||||
* }
|
||||
* </code>
|
||||
* This interface is exists basically so that $object instanceof DBField checks work
|
||||
*/
|
||||
abstract class DBField extends ModelData implements DBIndexable
|
||||
interface DBField extends DBIndexable
|
||||
{
|
||||
|
||||
/**
|
||||
* Raw value of this field
|
||||
*/
|
||||
protected mixed $value = null;
|
||||
|
||||
/**
|
||||
* Table this field belongs to
|
||||
*/
|
||||
protected ?string $tableName = null;
|
||||
|
||||
/**
|
||||
* Name of this field
|
||||
*/
|
||||
protected ?string $name = null;
|
||||
|
||||
/**
|
||||
* Used for generating DB schema. {@see DBSchemaManager}
|
||||
* Despite its name, this seems to be a string
|
||||
*/
|
||||
protected $arrayValue;
|
||||
|
||||
/**
|
||||
* Optional parameters for this field
|
||||
*/
|
||||
protected array $options = [];
|
||||
|
||||
/**
|
||||
* The escape type for this field when inserted into a template - either "xml" or "raw".
|
||||
*/
|
||||
private static string $escape_type = 'raw';
|
||||
|
||||
/**
|
||||
* Subclass of {@link SearchFilter} for usage in {@link defaultSearchFilter()}.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
private static string|bool $index = false;
|
||||
|
||||
private static array $casting = [
|
||||
'ATT' => 'HTMLFragment',
|
||||
'CDATA' => 'HTMLFragment',
|
||||
'HTML' => 'HTMLFragment',
|
||||
'HTMLATT' => 'HTMLFragment',
|
||||
'JS' => 'HTMLFragment',
|
||||
'RAW' => 'HTMLFragment',
|
||||
'RAWURLATT' => 'HTMLFragment',
|
||||
'URLATT' => 'HTMLFragment',
|
||||
'XML' => 'HTMLFragment',
|
||||
'ProcessedRAW' => 'HTMLFragment',
|
||||
];
|
||||
|
||||
/**
|
||||
* 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 mixed $defaultVal = null;
|
||||
|
||||
/**
|
||||
* Provide the DBField name and an array of options, e.g. ['index' => true], or ['nullifyEmpty' => false]
|
||||
*
|
||||
* @throws InvalidArgumentException If $options was passed by not an array
|
||||
*/
|
||||
public function __construct(?string $name = null, array $options = [])
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
if ($options) {
|
||||
if (!is_array($options)) {
|
||||
throw new InvalidArgumentException("Invalid options $options");
|
||||
}
|
||||
$this->setOptions($options);
|
||||
}
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a DBField object that's not bound to any particular field.
|
||||
*
|
||||
* Useful for accessing the classes behaviour for other parts of your code.
|
||||
*
|
||||
* @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 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
|
||||
*/
|
||||
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
|
||||
if ($args && strpos($spec ?? '', '(') !== false) {
|
||||
trigger_error('Additional args provided in both $spec and $args', E_USER_WARNING);
|
||||
}
|
||||
// Ensure name is always first argument
|
||||
array_unshift($args, $name);
|
||||
|
||||
/** @var DBField $dbField */
|
||||
$dbField = Injector::inst()->createWithArgs($spec, $args);
|
||||
$dbField->setValue($value, null, false);
|
||||
return $dbField;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of this field.
|
||||
*
|
||||
* The name should never be altered, but it if was never given a name in
|
||||
* the first place you can set a name.
|
||||
*
|
||||
* If you try an alter the name a warning will be thrown.
|
||||
*/
|
||||
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."
|
||||
. "It's partially immutable - it shouldn't be altered after it's given a value.", E_USER_WARNING);
|
||||
}
|
||||
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of this field.
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name ?? '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value of this field.
|
||||
*/
|
||||
public function getValue(): mixed
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of this field in various formats.
|
||||
* Used by {@link DataObject->getField()}, {@link DataObject->setCastedField()}
|
||||
* {@link DataObject->dbObject()} and {@link DataObject->write()}.
|
||||
*
|
||||
* As this method is used both for initializing the field after construction,
|
||||
* and actually changing its values, it needs a {@link $markChanged}
|
||||
* parameter.
|
||||
*
|
||||
* @param null|ModelData|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.
|
||||
*/
|
||||
public function setValue(mixed $value, null|array|ModelData $record = null, bool $markChanged = true): static
|
||||
{
|
||||
$this->value = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default value assigned at the DB level
|
||||
*/
|
||||
public function getDefaultValue(): mixed
|
||||
{
|
||||
return $this->defaultVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default value to use at the DB level
|
||||
*/
|
||||
public function setDefaultValue(mixed $defaultValue): static
|
||||
{
|
||||
$this->defaultVal = $defaultValue;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the optional parameters for this field
|
||||
*/
|
||||
public function setOptions(array $options = []): static
|
||||
{
|
||||
$this->options = $options;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get optional parameters for this field
|
||||
*/
|
||||
public function getOptions(): array
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
public function setIndexType($type): string|bool
|
||||
{
|
||||
if (!is_bool($type)
|
||||
&& !in_array($type, [DBIndexable::TYPE_INDEX, DBIndexable::TYPE_UNIQUE, DBIndexable::TYPE_FULLTEXT])
|
||||
) {
|
||||
throw new \InvalidArgumentException(
|
||||
"{$type} is not a valid index type or boolean. Please see DBIndexable."
|
||||
);
|
||||
}
|
||||
|
||||
$this->options['index'] = $type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIndexType()
|
||||
{
|
||||
if (array_key_exists('index', $this->options ?? [])) {
|
||||
$type = $this->options['index'];
|
||||
} else {
|
||||
$type = static::config()->get('index');
|
||||
}
|
||||
|
||||
if (is_bool($type)) {
|
||||
if (!$type) {
|
||||
return false;
|
||||
}
|
||||
$type = DBIndexable::TYPE_DEFAULT;
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the field has a value which is not considered to be 'null'
|
||||
* in a database context.
|
||||
*/
|
||||
public function exists(): bool
|
||||
{
|
||||
return (bool)$this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transformed value ready to be sent to the database. This value
|
||||
* will be escaped automatically by the prepared query processor, so it
|
||||
* should not be escaped or quoted at all.
|
||||
*
|
||||
* @param mixed $value The value to check
|
||||
* @return mixed The raw value, or escaped parameterised details
|
||||
*/
|
||||
public function prepValueForDB(mixed $value): mixed
|
||||
{
|
||||
if ($value === null ||
|
||||
$value === "" ||
|
||||
$value === false ||
|
||||
($this->scalarValueOnly() && !is_scalar($value))
|
||||
) {
|
||||
return null;
|
||||
} else {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the current field for usage in a
|
||||
* database-manipulation (works on a manipulation reference).
|
||||
*
|
||||
* Make value safe for insertion into
|
||||
* a SQL SET statement by applying addslashes() -
|
||||
* can also be used to apply special SQL-commands
|
||||
* to the raw value (e.g. for GIS functionality).
|
||||
* {@see prepValueForDB}
|
||||
*/
|
||||
public function writeToManipulation(array &$manipulation): void
|
||||
{
|
||||
$manipulation['fields'][$this->name] = $this->exists()
|
||||
? $this->prepValueForDB($this->value) : $this->nullValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom query parameters for this field,
|
||||
* mostly SELECT statements for multi-value fields.
|
||||
*
|
||||
* By default, the ORM layer does a
|
||||
* SELECT <tablename>.* which
|
||||
* gets you the default representations
|
||||
* of all columns.
|
||||
*/
|
||||
public function addToQuery(SQLSelect &$query)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign this DBField to a table
|
||||
*/
|
||||
public function setTable(string $tableName): static
|
||||
{
|
||||
$this->tableName = $tableName;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the table this field belongs to, if assigned
|
||||
*/
|
||||
public function getTable(): ?string
|
||||
{
|
||||
return $this->tableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine 'default' casting for this field.
|
||||
*/
|
||||
public function forTemplate(): string
|
||||
{
|
||||
// Default to XML encoding
|
||||
return $this->XML();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value appropriate for a HTML attribute string
|
||||
*/
|
||||
public function HTMLATT(): string
|
||||
{
|
||||
return Convert::raw2htmlatt($this->RAW());
|
||||
}
|
||||
|
||||
/**
|
||||
* urlencode this string
|
||||
*/
|
||||
public function URLATT(): string
|
||||
{
|
||||
return urlencode($this->RAW() ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* rawurlencode this string
|
||||
*/
|
||||
public function RAWURLATT(): string
|
||||
{
|
||||
return rawurlencode($this->RAW() ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value appropriate for a HTML attribute string
|
||||
*/
|
||||
public function ATT(): string
|
||||
{
|
||||
return Convert::raw2att($this->RAW());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the raw value for this field.
|
||||
* Note: Skips processors implemented via forTemplate()
|
||||
*/
|
||||
public function RAW(): mixed
|
||||
{
|
||||
return $this->getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets javascript string literal value
|
||||
*/
|
||||
public function JS(): string
|
||||
{
|
||||
return Convert::raw2js($this->RAW());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return JSON encoded value
|
||||
*/
|
||||
public function JSON(): string
|
||||
{
|
||||
return json_encode($this->RAW());
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias for {@see XML()}
|
||||
*/
|
||||
public function HTML(): string
|
||||
{
|
||||
return $this->XML();
|
||||
}
|
||||
|
||||
/**
|
||||
* XML encode this value
|
||||
*/
|
||||
public function XML(): string
|
||||
{
|
||||
return Convert::raw2xml($this->RAW());
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely escape for XML string
|
||||
*/
|
||||
public function CDATA(): string
|
||||
{
|
||||
return $this->XML();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value to be set in the database to blank this field.
|
||||
* Usually it's a choice between null, 0, and ''
|
||||
*/
|
||||
public function nullValue(): mixed
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves this field to the given data object.
|
||||
*/
|
||||
public function saveInto(ModelData $model): void
|
||||
{
|
||||
$fieldName = $this->name;
|
||||
if (empty($fieldName)) {
|
||||
throw new \BadMethodCallException(
|
||||
"DBField::saveInto() Called on a nameless '" . static::class . "' object"
|
||||
);
|
||||
}
|
||||
if ($this->value instanceof DBField) {
|
||||
$this->value->saveInto($model);
|
||||
} else {
|
||||
$model->__set($fieldName, $this->value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a FormField instance used as a default
|
||||
* for form scaffolding.
|
||||
*
|
||||
* Used by {@link SearchContext}, {@link ModelAdmin}, {@link DataObject::scaffoldFormFields()}
|
||||
*
|
||||
* @param string $title Optional. Localized title of the generated instance
|
||||
*/
|
||||
public function scaffoldFormField(?string $title = null, array $params = []): ?FormField
|
||||
{
|
||||
return TextField::create($this->name, $title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a FormField instance used as a default
|
||||
* for searchform scaffolding.
|
||||
*
|
||||
* Used by {@link SearchContext}, {@link ModelAdmin}, {@link DataObject::scaffoldFormFields()}.
|
||||
*
|
||||
* @param string $title Optional. Localized title of the generated instance
|
||||
*/
|
||||
public function scaffoldSearchField(?string $title = null): ?FormField
|
||||
{
|
||||
return $this->scaffoldFormField($title);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name Override name of this field
|
||||
*/
|
||||
public function defaultSearchFilter(?string $name = null): SearchFilter
|
||||
{
|
||||
$name = ($name) ? $name : $this->name;
|
||||
$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(): void;
|
||||
|
||||
public function debug(): string
|
||||
{
|
||||
return <<<DBG
|
||||
<ul>
|
||||
<li><b>Name:</b>{$this->name}</li>
|
||||
<li><b>Table:</b>{$this->tableName}</li>
|
||||
<li><b>Value:</b>{$this->value}</li>
|
||||
</ul>
|
||||
DBG;
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
return (string)$this->forTemplate();
|
||||
}
|
||||
|
||||
public function getArrayValue()
|
||||
{
|
||||
return $this->arrayValue;
|
||||
}
|
||||
|
||||
public function setArrayValue($value): static
|
||||
{
|
||||
$this->arrayValue = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get formfield schema value for use in formschema response
|
||||
*/
|
||||
public function getSchemaValue(): mixed
|
||||
{
|
||||
return $this->RAW();
|
||||
}
|
||||
|
||||
public function getIndexSpecs(): ?array
|
||||
{
|
||||
$type = $this->getIndexType();
|
||||
if ($type) {
|
||||
return [
|
||||
'type' => $type,
|
||||
'columns' => [$this->getName()],
|
||||
];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
public function scalarValueOnly(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
37
src/ORM/FieldType/DBFieldHelper.php
Normal file
37
src/ORM/FieldType/DBFieldHelper.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
|
||||
class DBFieldHelper
|
||||
{
|
||||
/**
|
||||
* Create a DBField object that's not bound to any particular field.
|
||||
*
|
||||
* Useful for accessing the classes behaviour for other parts of your code.
|
||||
*
|
||||
* @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 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
|
||||
*/
|
||||
public static function create_field(string $spec, mixed $value, ?string $name = null, mixed ...$args): DBField
|
||||
{
|
||||
// Raise warning if inconsistent with DataObject::dbObject() behaviour
|
||||
// This will cause spec args to be shifted down by the number of provided $args
|
||||
if ($args && strpos($spec ?? '', '(') !== false) {
|
||||
trigger_error('Additional args provided in both $spec and $args', E_USER_WARNING);
|
||||
}
|
||||
// Ensure name is always first argument
|
||||
array_unshift($args, $name);
|
||||
|
||||
$dbField = Injector::inst()->createWithArgs($spec, $args);
|
||||
/** @var DBFieldTrait $dbField */
|
||||
$dbField->setValue($value, null, false);
|
||||
/** @var DBField $dbField */
|
||||
return $dbField;
|
||||
}
|
||||
}
|
345
src/ORM/FieldType/DBFieldTrait.php
Normal file
345
src/ORM/FieldType/DBFieldTrait.php
Normal file
@ -0,0 +1,345 @@
|
||||
<?php
|
||||
|
||||
namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Model\ModelData;
|
||||
use SilverStripe\ORM\Queries\SQLSelect;
|
||||
use SilverStripe\ORM\Filters\SearchFilter;
|
||||
use SilverStripe\Model\ModelFields\ModelField;
|
||||
use SilverStripe\Model\ModelFields\ModelFieldTrait;
|
||||
use SilverStripe\Model\ModelFields\StringModelField;
|
||||
|
||||
/**
|
||||
* Single field in the database.
|
||||
*
|
||||
* Every field from the database is represented as a sub-class of DBField.
|
||||
*
|
||||
* <b>Multi-value DBField objects</b>
|
||||
*
|
||||
* Sometimes you will want to make DBField classes that don't have a 1-1 match
|
||||
* to database fields. To do this, there are a number of fields for you to
|
||||
* overload:
|
||||
*
|
||||
* - Overload {@link writeToManipulation} to add the appropriate references to
|
||||
* the INSERT or UPDATE command
|
||||
* - Overload {@link addToQuery} to add the appropriate items to a SELECT
|
||||
* query's field list
|
||||
* - Add appropriate accessor methods
|
||||
*
|
||||
* <b>Subclass Example</b>
|
||||
*
|
||||
* The class is easy to overload with custom types, e.g. the MySQL "BLOB" type
|
||||
* (https://dev.mysql.com/doc/refman/8.4/en/blob.html).
|
||||
*
|
||||
* <code>
|
||||
* class Blob extends DBField {
|
||||
* function requireField(): void {
|
||||
* DB::require_field($this->tableName, $this->name, "blob");
|
||||
* }
|
||||
* }
|
||||
* </code>
|
||||
*/
|
||||
trait DBFieldTrait
|
||||
{
|
||||
/**
|
||||
* Raw value of this field
|
||||
*/
|
||||
protected mixed $value = null;
|
||||
|
||||
/**
|
||||
* Name of this field
|
||||
*/
|
||||
protected ?string $name = null;
|
||||
|
||||
/**
|
||||
* Table this field belongs to
|
||||
*/
|
||||
protected ?string $tableName = null;
|
||||
|
||||
/**
|
||||
* Used for generating DB schema. {@see DBSchemaManager}
|
||||
* Despite its name, this seems to be a string
|
||||
*/
|
||||
protected $arrayValue;
|
||||
|
||||
/**
|
||||
* Optional parameters for this field
|
||||
*/
|
||||
protected array $options = [];
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
private static string|bool $index = false;
|
||||
|
||||
/**
|
||||
* Subclass of {@link SearchFilter} for usage in {@link defaultSearchFilter()}.
|
||||
*/
|
||||
private static string $default_search_filter_class = 'PartialMatchFilter';
|
||||
|
||||
/**
|
||||
* 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 mixed $defaultVal = null;
|
||||
|
||||
/**
|
||||
* Provide the DBField name and an array of options, e.g. ['index' => true], or ['nullifyEmpty' => false]
|
||||
*
|
||||
* @throws InvalidArgumentException If $options was passed by not an array
|
||||
*/
|
||||
public function __construct(?string $name = null, array $options = [])
|
||||
{
|
||||
if (!is_a(self::class, ModelField::class, true)) {
|
||||
throw new InvalidArgumentException(
|
||||
'DBFieldTrait can only be used on classes that extend ' . ModelField::class
|
||||
);
|
||||
}
|
||||
if (!is_a(self::class, DBField::class, true)) {
|
||||
throw new InvalidArgumentException(
|
||||
'DBFieldTrait can only be used on classes that implement ' . DBField::class
|
||||
);
|
||||
}
|
||||
if ($options) {
|
||||
if (!is_array($options)) {
|
||||
throw new InvalidArgumentException("Invalid options $options");
|
||||
}
|
||||
$this->setOptions($options);
|
||||
}
|
||||
parent::__construct($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of this field.
|
||||
*
|
||||
* The name should never be altered, but it if was never given a name in
|
||||
* the first place you can set a name.
|
||||
*
|
||||
* If you try an alter the name a warning will be thrown.
|
||||
*/
|
||||
public function setName(?string $name): static
|
||||
{
|
||||
if ($this->name && $this->name !== $name) {
|
||||
user_error("ModelField::setName() shouldn't be called once a ModelField already has a name."
|
||||
. "It's partially immutable - it shouldn't be altered after it's given a value.", E_USER_WARNING);
|
||||
}
|
||||
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the value of this field in various formats.
|
||||
* Used by {@link DataObject->getField()}, {@link DataObject->setCastedField()}
|
||||
* {@link DataObject->dbObject()} and {@link DataObject->write()}.
|
||||
*
|
||||
* As this method is used both for initializing the field after construction,
|
||||
* and actually changing its values, it needs a {@link $markChanged}
|
||||
* parameter.
|
||||
*
|
||||
* @param null|ModelData|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.
|
||||
*/
|
||||
public function setValue(mixed $value, null|array|ModelData $record = null, bool $markChanged = true): static
|
||||
{
|
||||
$this->value = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the field to the underlying database.
|
||||
*/
|
||||
abstract public function requireField(): void;
|
||||
|
||||
/**
|
||||
* Get default value assigned at the DB level
|
||||
*/
|
||||
public function getDefaultValue(): mixed
|
||||
{
|
||||
return $this->defaultVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set default value to use at the DB level
|
||||
*/
|
||||
public function setDefaultValue(mixed $defaultValue): static
|
||||
{
|
||||
$this->defaultVal = $defaultValue;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the optional parameters for this field
|
||||
*/
|
||||
public function setOptions(array $options = []): static
|
||||
{
|
||||
$this->options = $options;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get optional parameters for this field
|
||||
*/
|
||||
public function getOptions(): array
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
public function setIndexType($type): string|bool
|
||||
{
|
||||
if (!is_bool($type)
|
||||
&& !in_array($type, [DBIndexable::TYPE_INDEX, DBIndexable::TYPE_UNIQUE, DBIndexable::TYPE_FULLTEXT])
|
||||
) {
|
||||
throw new \InvalidArgumentException(
|
||||
"{$type} is not a valid index type or boolean. Please see DBIndexable."
|
||||
);
|
||||
}
|
||||
|
||||
$this->options['index'] = $type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIndexType()
|
||||
{
|
||||
if (array_key_exists('index', $this->options ?? [])) {
|
||||
$type = $this->options['index'];
|
||||
} else {
|
||||
$type = static::config()->get('index');
|
||||
}
|
||||
|
||||
if (is_bool($type)) {
|
||||
if (!$type) {
|
||||
return false;
|
||||
}
|
||||
$type = DBIndexable::TYPE_DEFAULT;
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if the field has a value which is not considered to be 'null'
|
||||
* in a database context.
|
||||
*/
|
||||
public function exists(): bool
|
||||
{
|
||||
return (bool)$this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the transformed value ready to be sent to the database. This value
|
||||
* will be escaped automatically by the prepared query processor, so it
|
||||
* should not be escaped or quoted at all.
|
||||
*
|
||||
* @param mixed $value The value to check
|
||||
* @return mixed The raw value, or escaped parameterised details
|
||||
*/
|
||||
public function prepValueForDB(mixed $value): mixed
|
||||
{
|
||||
if ($value === null ||
|
||||
$value === "" ||
|
||||
$value === false ||
|
||||
($this->scalarValueOnly() && !is_scalar($value))
|
||||
) {
|
||||
return null;
|
||||
} else {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare the current field for usage in a
|
||||
* database-manipulation (works on a manipulation reference).
|
||||
*
|
||||
* Make value safe for insertion into
|
||||
* a SQL SET statement by applying addslashes() -
|
||||
* can also be used to apply special SQL-commands
|
||||
* to the raw value (e.g. for GIS functionality).
|
||||
* {@see prepValueForDB}
|
||||
*/
|
||||
public function writeToManipulation(array &$manipulation): void
|
||||
{
|
||||
$manipulation['fields'][$this->name] = $this->exists()
|
||||
? $this->prepValueForDB($this->value) : $this->nullValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom query parameters for this field,
|
||||
* mostly SELECT statements for multi-value fields.
|
||||
*
|
||||
* By default, the ORM layer does a
|
||||
* SELECT <tablename>.* which
|
||||
* gets you the default representations
|
||||
* of all columns.
|
||||
*/
|
||||
public function addToQuery(SQLSelect &$query)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign this DBField to a table
|
||||
*/
|
||||
public function setTable(string $tableName): static
|
||||
{
|
||||
$this->tableName = $tableName;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the table this field belongs to, if assigned
|
||||
*/
|
||||
public function getTable(): ?string
|
||||
{
|
||||
return $this->tableName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the value to be set in the database to blank this field.
|
||||
* Usually it's a choice between null, 0, and ''
|
||||
*/
|
||||
public function nullValue(): mixed
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name Override name of this field
|
||||
*/
|
||||
public function defaultSearchFilter(?string $name = null): SearchFilter
|
||||
{
|
||||
$name = ($name) ? $name : $this->name;
|
||||
$filterClass = static::config()->get('default_search_filter_class');
|
||||
return Injector::inst()->create($filterClass, $name);
|
||||
}
|
||||
|
||||
public function getArrayValue()
|
||||
{
|
||||
return $this->arrayValue;
|
||||
}
|
||||
|
||||
public function setArrayValue($value): static
|
||||
{
|
||||
$this->arrayValue = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIndexSpecs(): ?array
|
||||
{
|
||||
$type = $this->getIndexType();
|
||||
if ($type) {
|
||||
return [
|
||||
'type' => $type,
|
||||
'columns' => [$this->getName()],
|
||||
];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -5,12 +5,17 @@ namespace SilverStripe\ORM\FieldType;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\Forms\NumericField;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\FieldType\DBFieldTrait;
|
||||
use SilverStripe\Model\ModelFields\ModelField;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
|
||||
/**
|
||||
* Represents a floating point field.
|
||||
*/
|
||||
class DBFloat extends DBField
|
||||
class DBFloat extends ModelField implements DBField
|
||||
{
|
||||
use DBFieldTrait;
|
||||
|
||||
public function __construct(?string $name = null, float|int $defaultVal = 0)
|
||||
{
|
||||
$this->defaultVal = is_float($defaultVal) ? $defaultVal : (float) 0;
|
||||
|
@ -8,12 +8,16 @@ use SilverStripe\Model\List\ArrayList;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\Model\List\SS_List;
|
||||
use SilverStripe\Model\ArrayData;
|
||||
use SilverStripe\Model\ModelFields\ModelField;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
|
||||
/**
|
||||
* Represents a signed 32 bit integer field.
|
||||
*/
|
||||
class DBInt extends DBField
|
||||
class DBInt extends ModelField implements DBField
|
||||
{
|
||||
use DBFieldTrait;
|
||||
|
||||
public function __construct(?string $name = null, int $defaultVal = 0)
|
||||
{
|
||||
$this->defaultVal = is_int($defaultVal) ? $defaultVal : 0;
|
||||
|
@ -2,19 +2,15 @@
|
||||
|
||||
namespace SilverStripe\ORM\FieldType;
|
||||
|
||||
use SilverStripe\Model\ModelFields\StringModelField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldTrait;
|
||||
|
||||
/**
|
||||
* An abstract base class for the string field types (i.e. Varchar and Text)
|
||||
*/
|
||||
abstract class DBString extends DBField
|
||||
abstract class DBString extends StringModelField implements DBField
|
||||
{
|
||||
private static array $casting = [
|
||||
'LimitCharacters' => 'Text',
|
||||
'LimitCharactersToClosestWord' => 'Text',
|
||||
'LimitWordCount' => 'Text',
|
||||
'LowerCase' => 'Text',
|
||||
'UpperCase' => 'Text',
|
||||
'Plain' => 'Text',
|
||||
];
|
||||
use DBFieldTrait;
|
||||
|
||||
/**
|
||||
* Set the default value for "nullify empty"
|
||||
@ -95,127 +91,4 @@ abstract class DBString extends DBField
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
public function forTemplate(): string
|
||||
{
|
||||
return nl2br(parent::forTemplate() ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Limit this field's content by a number of characters.
|
||||
* This makes use of strip_tags() to avoid malforming the
|
||||
* HTML tags in the string of text.
|
||||
*
|
||||
* @param int $limit Number of characters to limit by
|
||||
* @param string|false $add Ellipsis to add to the end of truncated string
|
||||
*/
|
||||
public function LimitCharacters(int $limit = 20, string|false $add = false): string
|
||||
{
|
||||
$value = $this->Plain();
|
||||
if (mb_strlen($value ?? '') <= $limit) {
|
||||
return $value;
|
||||
}
|
||||
return $this->addEllipsis(mb_substr($value ?? '', 0, $limit), $add);
|
||||
}
|
||||
|
||||
/**
|
||||
* Limit this field's content by a number of characters and truncate
|
||||
* the field to the closest complete word. All HTML tags are stripped
|
||||
* from the field.
|
||||
*
|
||||
* @param int $limit Number of characters to limit by
|
||||
* @param string|false $add Ellipsis to add to the end of truncated string
|
||||
* @return string Plain text value with limited characters
|
||||
*/
|
||||
public function LimitCharactersToClosestWord(int $limit = 20, string|false $add = false): string
|
||||
{
|
||||
// Safely convert to plain text
|
||||
$value = $this->Plain();
|
||||
|
||||
// Determine if value exceeds limit before limiting characters
|
||||
if (mb_strlen($value ?? '') <= $limit) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Limit to character limit
|
||||
$value = mb_substr($value ?? '', 0, $limit);
|
||||
|
||||
// If value exceeds limit, strip punctuation off the end to the last space and apply ellipsis
|
||||
$value = $this->addEllipsis(
|
||||
preg_replace(
|
||||
'/[^\w_]+$/',
|
||||
'',
|
||||
mb_substr($value ?? '', 0, mb_strrpos($value ?? '', " "))
|
||||
),
|
||||
$add
|
||||
);
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Limit this field's content by a number of words.
|
||||
*
|
||||
* @param int $numWords Number of words to limit by.
|
||||
* @param string|false $add Ellipsis to add to the end of truncated string.
|
||||
*/
|
||||
public function LimitWordCount(int $numWords = 26, string|false $add = false): string
|
||||
{
|
||||
$value = $this->Plain();
|
||||
$words = explode(' ', $value ?? '');
|
||||
if (count($words ?? []) <= $numWords) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Limit
|
||||
$words = array_slice($words ?? [], 0, $numWords);
|
||||
return $this->addEllipsis(implode(' ', $words), $add);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the current value for this StringField to lowercase.
|
||||
*
|
||||
* @return string Text with lowercase (HTML for some subclasses)
|
||||
*/
|
||||
public function LowerCase(): string
|
||||
{
|
||||
return mb_strtolower($this->RAW() ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the current value for this StringField to uppercase.
|
||||
*
|
||||
* @return string Text with uppercase (HTML for some subclasses)
|
||||
*/
|
||||
public function UpperCase(): string
|
||||
{
|
||||
return mb_strtoupper($this->RAW() ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Plain text version of this string
|
||||
*/
|
||||
public function Plain(): string
|
||||
{
|
||||
return trim($this->RAW() ?? '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Swap add for defaultEllipsis if need be
|
||||
*/
|
||||
private function addEllipsis(string $string, string|false $add): string
|
||||
{
|
||||
if ($add === false) {
|
||||
$add = $this->defaultEllipsis();
|
||||
}
|
||||
|
||||
return $string . $add;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default string to indicate that a string was cut off.
|
||||
*/
|
||||
public function defaultEllipsis(): string
|
||||
{
|
||||
return _t(DBString::class . '.ELLIPSIS', '…');
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,9 @@ use SilverStripe\ORM\DB;
|
||||
use SilverStripe\Security\Member;
|
||||
use SilverStripe\Security\Security;
|
||||
use SilverStripe\Model\ModelData;
|
||||
use SilverStripe\ORM\FieldType\DBFieldTrait;
|
||||
use SilverStripe\Model\ModelFields\ModelField;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
|
||||
/**
|
||||
* Represents a column in the database with the type 'Time'.
|
||||
@ -22,8 +25,10 @@ use SilverStripe\Model\ModelData;
|
||||
* );
|
||||
* </code>
|
||||
*/
|
||||
class DBTime extends DBField
|
||||
class DBTime extends ModelField implements DBField
|
||||
{
|
||||
use DBFieldTrait;
|
||||
|
||||
/**
|
||||
* Standard ISO format string for time in CLDR standard format
|
||||
*/
|
||||
|
@ -5,12 +5,17 @@ namespace SilverStripe\ORM\FieldType;
|
||||
use SilverStripe\Forms\DropdownField;
|
||||
use SilverStripe\Forms\FormField;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\FieldType\DBFieldTrait;
|
||||
use SilverStripe\Model\ModelFields\ModelField;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
|
||||
/**
|
||||
* Represents a single year field.
|
||||
*/
|
||||
class DBYear extends DBField
|
||||
class DBYear extends ModelField implements DBField
|
||||
{
|
||||
use DBFieldTrait;
|
||||
|
||||
public function requireField(): void
|
||||
{
|
||||
$parts = ['datatype' => 'year', 'precision' => 4, 'arrayValue' => $this->arrayValue];
|
||||
|
@ -11,6 +11,7 @@ use InvalidArgumentException;
|
||||
use SilverStripe\Core\Config\Configurable;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
|
||||
/**
|
||||
* Base class for filtering implementations,
|
||||
|
@ -9,6 +9,7 @@ use SilverStripe\Core\ArrayLib;
|
||||
use SilverStripe\Model\List\ArrayList;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
use SilverStripe\Model\List\SS_List;
|
||||
use SilverStripe\Model\ArrayData;
|
||||
|
||||
|
@ -10,6 +10,7 @@ use SilverStripe\ORM\FieldType\DBComposite;
|
||||
use InvalidArgumentException;
|
||||
use Exception;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
|
||||
/**
|
||||
* Subclass of {@link DataList} representing a many_many relation.
|
||||
|
@ -7,6 +7,7 @@ use SilverStripe\Model\List\Limitable;
|
||||
use SilverStripe\Model\List\Sortable;
|
||||
use SilverStripe\Model\List\SS_List;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
|
||||
/**
|
||||
* Abstract representation of a DB relation field, either saved or in memory
|
||||
|
@ -6,6 +6,7 @@ use InvalidArgumentException;
|
||||
use ArrayIterator;
|
||||
use SilverStripe\Model\List\ArrayList;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
use Traversable;
|
||||
|
||||
/**
|
||||
|
@ -10,6 +10,7 @@ use SilverStripe\Control\HTTPResponse;
|
||||
use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Core\Manifest\ModuleLoader;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
use SilverStripe\ORM\FieldType\DBHTMLText;
|
||||
use SilverStripe\View\Requirements;
|
||||
use SilverStripe\View\SSViewer;
|
||||
@ -197,7 +198,7 @@ PHP
|
||||
|
||||
// Show login
|
||||
$controller = $controller->customise([
|
||||
'Content' => DBField::create_field(DBHTMLText::class, _t(
|
||||
'Content' => DBFieldHelper::create_field(DBHTMLText::class, _t(
|
||||
__CLASS__ . '.SUCCESSCONTENT',
|
||||
'<p>Login success. If you are not automatically redirected ' . '<a target="_top" href="{link}">click here</a></p>',
|
||||
'Login message displayed in the cms popup once a user has re-authenticated themselves',
|
||||
|
@ -10,6 +10,7 @@ use SilverStripe\Control\RequestHandler;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\ORM\FieldType\DBDatetime;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
use SilverStripe\Core\Validation\ValidationException;
|
||||
use SilverStripe\Security\Authenticator;
|
||||
use SilverStripe\Security\IdentityStore;
|
||||
@ -83,7 +84,7 @@ class ChangePasswordHandler extends RequestHandler
|
||||
|
||||
$session = $this->getRequest()->getSession();
|
||||
if ($session->get('AutoLoginHash')) {
|
||||
$message = DBField::create_field(
|
||||
$message = DBFieldHelper::create_field(
|
||||
'HTMLFragment',
|
||||
'<p>' . _t(
|
||||
'SilverStripe\\Security\\Security.ENTERNEWPASSWORD',
|
||||
@ -100,7 +101,7 @@ class ChangePasswordHandler extends RequestHandler
|
||||
|
||||
if (Security::getCurrentUser()) {
|
||||
// Logged in user requested a password change form.
|
||||
$message = DBField::create_field(
|
||||
$message = DBFieldHelper::create_field(
|
||||
'HTMLFragment',
|
||||
'<p>' . _t(
|
||||
'SilverStripe\\Security\\Security.CHANGEPASSWORDBELOW',
|
||||
@ -115,7 +116,7 @@ class ChangePasswordHandler extends RequestHandler
|
||||
}
|
||||
// Show a friendly message saying the login token has expired
|
||||
if ($token !== null && $member && !$member->validateAutoLoginToken($token)) {
|
||||
$message = DBField::create_field(
|
||||
$message = DBFieldHelper::create_field(
|
||||
'HTMLFragment',
|
||||
_t(
|
||||
'SilverStripe\\Security\\Security.NOTERESETLINKINVALID',
|
||||
|
@ -176,7 +176,7 @@ class CookieAuthenticationHandler implements AuthenticationHandler
|
||||
}
|
||||
|
||||
// Renew the token
|
||||
Deprecation::withNoReplacement(fn() => $rememberLoginHash->renew());
|
||||
Deprecation::withSuppressedNotice(fn() => $rememberLoginHash->renew());
|
||||
|
||||
// Send the new token to the client if it was changed
|
||||
if ($rememberLoginHash->getToken()) {
|
||||
|
@ -11,6 +11,7 @@ use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Forms\Form;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
use SilverStripe\Security\Member;
|
||||
use SilverStripe\Security\Security;
|
||||
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
|
||||
@ -92,7 +93,7 @@ class LostPasswordHandler extends RequestHandler
|
||||
);
|
||||
|
||||
return [
|
||||
'Content' => DBField::create_field('HTMLFragment', "<p>$message</p>"),
|
||||
'Content' => DBFieldHelper::create_field('HTMLFragment', "<p>$message</p>"),
|
||||
'Form' => $this->lostPasswordForm(),
|
||||
];
|
||||
}
|
||||
@ -115,7 +116,7 @@ class LostPasswordHandler extends RequestHandler
|
||||
'SilverStripe\\Security\\Security.PASSWORDRESETSENTHEADER',
|
||||
"Password reset link sent"
|
||||
),
|
||||
'Content' => DBField::create_field('HTMLFragment', "<p>$message</p>"),
|
||||
'Content' => DBFieldHelper::create_field('HTMLFragment', "<p>$message</p>"),
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -22,6 +22,7 @@ use SilverStripe\Model\List\ArrayList;
|
||||
use SilverStripe\ORM\DataObject;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
use SilverStripe\ORM\FieldType\DBHTMLText;
|
||||
use SilverStripe\Core\Validation\ValidationResult;
|
||||
use SilverStripe\Model\ArrayData;
|
||||
@ -911,8 +912,8 @@ class Security extends Controller implements TemplateGlobalProvider
|
||||
$fragments = array_merge(['Title' => $title], $fragments);
|
||||
if ($message) {
|
||||
$messageResult = [
|
||||
'Content' => DBField::create_field('HTMLFragment', $message),
|
||||
'Message' => DBField::create_field('HTMLFragment', $message),
|
||||
'Content' => DBFieldHelper::create_field('HTMLFragment', $message),
|
||||
'Message' => DBFieldHelper::create_field('HTMLFragment', $message),
|
||||
'MessageType' => $messageType
|
||||
];
|
||||
$fragments = array_merge($fragments, $messageResult);
|
||||
|
@ -17,7 +17,7 @@ use SilverStripe\Core\Manifest\ResourceURLGenerator;
|
||||
use SilverStripe\Core\Path;
|
||||
use SilverStripe\Dev\Debug;
|
||||
use SilverStripe\i18n\i18n;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
use Symfony\Component\Filesystem\Path as FilesystemPath;
|
||||
|
||||
class Requirements_Backend
|
||||
@ -1035,8 +1035,8 @@ class Requirements_Backend
|
||||
i18n::config()->get('default_locale'),
|
||||
i18n::getData()->langFromLocale(i18n::get_locale()),
|
||||
i18n::get_locale(),
|
||||
strtolower(DBField::create_field('Locale', i18n::get_locale())->RFC1766() ?? ''),
|
||||
strtolower(DBField::create_field('Locale', i18n::config()->get('default_locale'))->RFC1766() ?? '')
|
||||
strtolower(DBFieldHelper::create_field('Locale', i18n::get_locale())->RFC1766() ?? ''),
|
||||
strtolower(DBFieldHelper::create_field('Locale', i18n::config()->get('default_locale'))->RFC1766() ?? '')
|
||||
];
|
||||
|
||||
$candidates = array_map(
|
||||
|
@ -11,7 +11,7 @@ use SilverStripe\Core\Flushable;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Core\Injector\Injectable;
|
||||
use SilverStripe\Control\Director;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
use SilverStripe\ORM\FieldType\DBHTMLText;
|
||||
use SilverStripe\Security\Permission;
|
||||
use InvalidArgumentException;
|
||||
@ -670,7 +670,7 @@ PHP;
|
||||
}
|
||||
|
||||
/** @var DBHTMLText $html */
|
||||
$html = DBField::create_field('HTMLFragment', $output);
|
||||
$html = DBFieldHelper::create_field('HTMLFragment', $output);
|
||||
|
||||
// Reset global state
|
||||
static::setRewriteHashLinksDefault($origRewriteDefault);
|
||||
|
@ -6,6 +6,7 @@ use InvalidArgumentException;
|
||||
use SilverStripe\Core\ClassInfo;
|
||||
use SilverStripe\Model\ModelData;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
|
||||
/**
|
||||
* This extends SSViewer_Scope to mix in data on top of what the item provides. This can be "global"
|
||||
@ -438,6 +439,6 @@ class SSViewer_DataPresenter extends SSViewer_Scope
|
||||
? ModelData::config()->uninherited('default_cast')
|
||||
: $source['casting'];
|
||||
|
||||
return DBField::create_field($casting, $value);
|
||||
return DBFieldHelper::create_field($casting, $value);
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ namespace SilverStripe\View;
|
||||
|
||||
use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
|
||||
/**
|
||||
* Special SSViewer that will process a template passed as a string, rather than a filename.
|
||||
@ -72,7 +73,7 @@ class SSViewer_FromString extends SSViewer
|
||||
unlink($cacheFile ?? '');
|
||||
}
|
||||
|
||||
$html = DBField::create_field('HTMLFragment', $val);
|
||||
$html = DBFieldHelper::create_field('HTMLFragment', $val);
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ use SilverStripe\ORM\FieldType\DBText;
|
||||
use SilverStripe\ORM\FieldType\DBFloat;
|
||||
use SilverStripe\ORM\FieldType\DBInt;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
|
||||
/**
|
||||
* This tracks the current scope for an SSViewer instance. It has three goals:
|
||||
|
@ -10,6 +10,7 @@ use SilverStripe\Core\Convert;
|
||||
use SilverStripe\Core\Injector\Injector;
|
||||
use SilverStripe\Model\List\ArrayList;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
use SilverStripe\Model\ArrayData;
|
||||
use SilverStripe\View\Embed\Embeddable;
|
||||
use SilverStripe\View\HTML;
|
||||
@ -197,7 +198,7 @@ class EmbedShortcodeProvider implements ShortcodeHandler
|
||||
$data = [
|
||||
'Arguments' => $arguments,
|
||||
'Attributes' => $attributes,
|
||||
'Content' => DBField::create_field('HTMLFragment', $content)
|
||||
'Content' => DBFieldHelper::create_field('HTMLFragment', $content)
|
||||
];
|
||||
|
||||
return ArrayData::create($data)->renderWith(EmbedShortcodeProvider::class . '_video')->forTemplate();
|
||||
|
@ -116,72 +116,72 @@ class DeprecationTest extends SapphireTest
|
||||
Deprecation::outputNotices();
|
||||
}
|
||||
|
||||
public function testWithNoReplacementDefault()
|
||||
public function testwithSuppressedNoticeDefault()
|
||||
{
|
||||
Deprecation::enable();
|
||||
$ret = Deprecation::withNoReplacement(function () {
|
||||
$ret = Deprecation::withSuppressedNotice(function () {
|
||||
return $this->myDeprecatedMethod();
|
||||
});
|
||||
$this->assertSame('abc', $ret);
|
||||
Deprecation::outputNotices();
|
||||
}
|
||||
|
||||
public function testWithNoReplacementTrue()
|
||||
public function testwithSuppressedNoticeTrue()
|
||||
{
|
||||
$message = implode(' ', [
|
||||
'SilverStripe\Dev\Tests\DeprecationTest->myDeprecatedMethod is deprecated.',
|
||||
'My message.',
|
||||
'Called from SilverStripe\Dev\Tests\DeprecationTest->testWithNoReplacementTrue.'
|
||||
'Called from SilverStripe\Dev\Tests\DeprecationTest->testwithSuppressedNoticeTrue.'
|
||||
]);
|
||||
$this->expectException(DeprecationTestException::class);
|
||||
$this->expectExceptionMessage($message);
|
||||
Deprecation::enable(true);
|
||||
$ret = Deprecation::withNoReplacement(function () {
|
||||
$ret = Deprecation::withSuppressedNotice(function () {
|
||||
return $this->myDeprecatedMethod();
|
||||
});
|
||||
$this->assertSame('abc', $ret);
|
||||
Deprecation::outputNotices();
|
||||
}
|
||||
|
||||
public function testWithNoReplacementTrueCallUserFunc()
|
||||
public function testwithSuppressedNoticeTrueCallUserFunc()
|
||||
{
|
||||
$message = implode(' ', [
|
||||
'SilverStripe\Dev\Tests\DeprecationTest->myDeprecatedMethod is deprecated.',
|
||||
'My message.',
|
||||
'Called from SilverStripe\Dev\Tests\DeprecationTest->testWithNoReplacementTrueCallUserFunc.'
|
||||
'Called from SilverStripe\Dev\Tests\DeprecationTest->testwithSuppressedNoticeTrueCallUserFunc.'
|
||||
]);
|
||||
$this->expectException(DeprecationTestException::class);
|
||||
$this->expectExceptionMessage($message);
|
||||
Deprecation::enable(true);
|
||||
$ret = Deprecation::withNoReplacement(function () {
|
||||
$ret = Deprecation::withSuppressedNotice(function () {
|
||||
return call_user_func([$this, 'myDeprecatedMethod']);
|
||||
});
|
||||
$this->assertSame('abc', $ret);
|
||||
Deprecation::outputNotices();
|
||||
}
|
||||
|
||||
public function testNoticeWithNoReplacementTrue()
|
||||
public function testNoticewithSuppressedNoticeTrue()
|
||||
{
|
||||
$message = implode(' ', [
|
||||
'SilverStripe\Dev\Tests\DeprecationTest->testNoticeWithNoReplacementTrue is deprecated.',
|
||||
'SilverStripe\Dev\Tests\DeprecationTest->testNoticewithSuppressedNoticeTrue is deprecated.',
|
||||
'My message.',
|
||||
'Called from PHPUnit\Framework\TestCase->runTest.'
|
||||
]);
|
||||
$this->expectException(DeprecationTestException::class);
|
||||
$this->expectExceptionMessage($message);
|
||||
Deprecation::enable(true);
|
||||
Deprecation::withNoReplacement(function () {
|
||||
Deprecation::withSuppressedNotice(function () {
|
||||
Deprecation::notice('123', 'My message.');
|
||||
});
|
||||
Deprecation::outputNotices();
|
||||
}
|
||||
|
||||
public function testClassWithNoReplacement()
|
||||
public function testClasswithSuppressedNotice()
|
||||
{
|
||||
$message = implode(' ', [
|
||||
'SilverStripe\Dev\Tests\DeprecationTest\DeprecationTestObject is deprecated.',
|
||||
'Some class message.',
|
||||
'Called from SilverStripe\Dev\Tests\DeprecationTest->testClassWithNoReplacement.'
|
||||
'Called from SilverStripe\Dev\Tests\DeprecationTest->testClasswithSuppressedNotice.'
|
||||
]);
|
||||
$this->expectException(DeprecationTestException::class);
|
||||
$this->expectExceptionMessage($message);
|
||||
@ -193,12 +193,12 @@ class DeprecationTest extends SapphireTest
|
||||
Deprecation::outputNotices();
|
||||
}
|
||||
|
||||
public function testClassWithInjectorWithNoReplacement()
|
||||
public function testClassWithInjectorwithSuppressedNotice()
|
||||
{
|
||||
$message = implode(' ', [
|
||||
'SilverStripe\Dev\Tests\DeprecationTest\DeprecationTestObject is deprecated.',
|
||||
'Some class message.',
|
||||
'Called from SilverStripe\Dev\Tests\DeprecationTest->testClassWithInjectorWithNoReplacement.'
|
||||
'Called from SilverStripe\Dev\Tests\DeprecationTest->testClassWithInjectorwithSuppressedNotice.'
|
||||
]);
|
||||
$this->expectException(DeprecationTestException::class);
|
||||
$this->expectExceptionMessage($message);
|
||||
|
@ -11,7 +11,7 @@ class DeprecationTestObject extends DataObject implements TestOnly
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
Deprecation::withNoReplacement(function () {
|
||||
Deprecation::withSuppressedNotice(function () {
|
||||
Deprecation::notice(
|
||||
'1.2.3',
|
||||
'Some class message',
|
||||
|
@ -6,6 +6,7 @@ use SilverStripe\Core\Config\Config;
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\DB;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
use SilverStripe\Model\ModelData;
|
||||
|
||||
class TestDbField extends DBField implements TestOnly
|
||||
|
@ -5,6 +5,7 @@ namespace SilverStripe\ORM\Tests\DataObjectTest;
|
||||
use SilverStripe\Dev\TestOnly;
|
||||
use SilverStripe\ORM\FieldType\DBBoolean;
|
||||
use SilverStripe\ORM\FieldType\DBField;
|
||||
use SilverStripe\ORM\FieldType\DBFieldHelper;
|
||||
|
||||
/**
|
||||
* This is a fake DB field specifically design to test dynamic value assignment. You can set `scalarValueOnly` in
|
||||
|
@ -156,7 +156,7 @@ class PasswordEncryptorTest extends SapphireTest
|
||||
'encryptors',
|
||||
['test_sha1legacy' => [PasswordEncryptor_LegacyPHPHash::class => 'sha1']]
|
||||
);
|
||||
$e = Deprecation::withNoReplacement(fn() => PasswordEncryptor::create_for_algorithm('test_sha1legacy'));
|
||||
$e = Deprecation::withSuppressedNotice(fn() => PasswordEncryptor::create_for_algorithm('test_sha1legacy'));
|
||||
// precomputed hashes for 'mypassword' from different architectures
|
||||
$amdHash = 'h1fj0a6m4o6k0sosks88oo08ko4gc4s';
|
||||
$intelHash = 'h1fj0a6m4o0g04ocg00o4kwoc4wowws';
|
||||
|
@ -111,7 +111,7 @@ class RememberLoginHashTest extends SapphireTest
|
||||
|
||||
$member = $this->objFromFixture(Member::class, 'main');
|
||||
|
||||
Deprecation::withNoReplacement(
|
||||
Deprecation::withSuppressedNotice(
|
||||
fn() => RememberLoginHash::config()->set('replace_token_during_session_renewal', $replaceToken)
|
||||
);
|
||||
|
||||
@ -122,7 +122,7 @@ class RememberLoginHashTest extends SapphireTest
|
||||
// Fetch the token from the DB - otherwise we still have the token from when this was originally created
|
||||
$storedHash = RememberLoginHash::get()->find('ID', $hash->ID);
|
||||
|
||||
Deprecation::withNoReplacement(fn() => $storedHash->renew());
|
||||
Deprecation::withSuppressedNotice(fn() => $storedHash->renew());
|
||||
|
||||
if ($replaceToken) {
|
||||
$this->assertNotEquals($oldToken, $storedHash->getToken());
|
||||
|
Loading…
x
Reference in New Issue
Block a user