Merge branch '5.2' into 5

This commit is contained in:
github-actions 2024-03-18 02:34:26 +00:00
commit 0d8626f0bc
6 changed files with 35 additions and 46 deletions

View File

@ -463,9 +463,9 @@ class HTTPRequest implements ArrayAccess
* <code>$this->setResponse(HTTPRequest::send_file('the content', 'filename.txt'));</code> * <code>$this->setResponse(HTTPRequest::send_file('the content', 'filename.txt'));</code>
* *
* @static * @static
* @param $fileData * @param string $fileData
* @param $fileName * @param string $fileName
* @param null $mimeType * @param string|null $mimeType
* @return HTTPResponse * @return HTTPResponse
*/ */
public static function send_file($fileData, $fileName, $mimeType = null) public static function send_file($fileData, $fileName, $mimeType = null)
@ -497,7 +497,7 @@ class HTTPRequest implements ArrayAccess
* The pattern can optionally start with an HTTP method and a space. For example, "POST $Controller/$Action". * The pattern can optionally start with an HTTP method and a space. For example, "POST $Controller/$Action".
* This is used to define a rule that only matches on a specific HTTP method. * This is used to define a rule that only matches on a specific HTTP method.
* *
* @param $pattern * @param string $pattern
* @param bool $shiftOnSuccess * @param bool $shiftOnSuccess
* @return array|bool * @return array|bool
*/ */
@ -679,7 +679,7 @@ class HTTPRequest implements ArrayAccess
} }
/** /**
* @param $params * @param array $params
* @return HTTPRequest $this * @return HTTPRequest $this
*/ */
public function setRouteParams($params) public function setRouteParams($params)
@ -805,7 +805,7 @@ class HTTPRequest implements ArrayAccess
* Sets the client IP address which originated this request. * Sets the client IP address which originated this request.
* Use setIPFromHeaderValue if assigning from header value. * Use setIPFromHeaderValue if assigning from header value.
* *
* @param $ip string * @param string $ip
* @return $this * @return $this
*/ */
public function setIP($ip) public function setIP($ip)

View File

@ -46,7 +46,7 @@ trait FileUploadReceiver
/** /**
* Parent data record. Will be inferred from parent form or controller if blank. * Parent data record. Will be inferred from parent form or controller if blank.
* *
* @var DataObject * @var ?DataObject
*/ */
protected $record; protected $record;
@ -78,7 +78,7 @@ trait FileUploadReceiver
* Get the record to use as "Parent" for uploaded Files (eg a Page with a has_one to File) If none is set, it will * Get the record to use as "Parent" for uploaded Files (eg a Page with a has_one to File) If none is set, it will
* use Form->getRecord() or Form->Controller()->data() * use Form->getRecord() or Form->Controller()->data()
* *
* @return DataObject * @return ?DataObject
*/ */
public function getRecord() public function getRecord()
{ {

View File

@ -370,7 +370,7 @@ class Form extends ViewableData implements HasRequestHandler
/** /**
* Helper to get current request for this form * Helper to get current request for this form
* *
* @return HTTPRequest * @return HTTPRequest|null
*/ */
protected function getRequest() protected function getRequest()
{ {
@ -425,7 +425,7 @@ class Form extends ViewableData implements HasRequestHandler
/** /**
* Return any ValidationResult instance stored for this object * Return any ValidationResult instance stored for this object
* *
* @return ValidationResult The ValidationResult object stored in the session * @return ValidationResult|null The ValidationResult object stored in the session
*/ */
public function getSessionValidationResult() public function getSessionValidationResult()
{ {
@ -1479,7 +1479,7 @@ class Form extends ViewableData implements HasRequestHandler
* It will make use of setCastedField() to do this. * It will make use of setCastedField() to do this.
* *
* @param ViewableData&DataObjectInterface $dataObject The object to save data into * @param ViewableData&DataObjectInterface $dataObject The object to save data into
* @param FieldList $fieldList An optional list of fields to process. This can be useful when you have a * @param array<string>|null $fieldList An optional list of fields to process. This can be useful when you have a
* form that has some fields that save to one object, and some that save to another. * form that has some fields that save to one object, and some that save to another.
*/ */
public function saveInto(DataObjectInterface $dataObject, $fieldList = null) public function saveInto(DataObjectInterface $dataObject, $fieldList = null)
@ -1610,7 +1610,7 @@ class Form extends ViewableData implements HasRequestHandler
* Return the default button that should be clicked when another one isn't * Return the default button that should be clicked when another one isn't
* available. * available.
* *
* @return FormAction * @return FormAction|null
*/ */
public function defaultAction() public function defaultAction()
{ {

View File

@ -101,10 +101,20 @@ class NumericField extends TextField
return NumberFormatter::TYPE_DOUBLE; return NumberFormatter::TYPE_DOUBLE;
} }
/**
* In some cases and locales, validation expects non-breaking spaces.
* This homogenises regular, narrow and thin non-breaking spaces to a regular space character.
*
*/
private function clean(?string $value): string
{
return trim(str_replace(["\u{00A0}", "\u{202F}", "\u{2009}"], ' ', $value ?? ''));
}
public function setSubmittedValue($value, $data = null) public function setSubmittedValue($value, $data = null)
{ {
// Save original value in case parse fails // Save original value in case parse fails
$value = trim($value ?? ''); $value = $this->clean($value);
$this->originalValue = $value; $this->originalValue = $value;
// Empty string is no-number (not 0) // Empty string is no-number (not 0)

View File

@ -356,7 +356,7 @@ class DataList extends ViewableData implements SS_List, Filterable, Sortable, Li
* *
* Raw SQL is not accepted, only actual field names can be passed * Raw SQL is not accepted, only actual field names can be passed
* *
* @param string|array $args * @param string|array|null $args
* @example $list = $list->sort('Name'); // default ASC sorting * @example $list = $list->sort('Name'); // default ASC sorting
* @example $list = $list->sort('"Name"'); // field names can have double quotes around them * @example $list = $list->sort('"Name"'); // field names can have double quotes around them
* @example $list = $list->sort('Name ASC, Age DESC'); * @example $list = $list->sort('Name ASC, Age DESC');

View File

@ -11,27 +11,6 @@ class NumericFieldTest extends SapphireTest
{ {
protected $usesDatabase = false; protected $usesDatabase = false;
/**
* In some cases and locales, validation expects non-breaking spaces.
* This homogenises narrow and regular NBSPs to a regular space character
*
* Duplicates non-public NumericField::clean method
*
* @param string $input
* @return string The input value, with all non-breaking spaces replaced with spaces
*/
protected function clean($input)
{
return str_replace(
[
html_entity_decode('&nbsp;', 0, 'UTF-8'),
html_entity_decode('&#8239;', 0, 'UTF-8'), // narrow non-breaking space
],
' ',
trim($input ?? '')
);
}
/** /**
* Test that data loaded in via Form::loadDataFrom(DataObject) will populate the field correctly, * Test that data loaded in via Form::loadDataFrom(DataObject) will populate the field correctly,
* and can format the database value appropriately for the frontend * and can format the database value appropriately for the frontend
@ -64,8 +43,8 @@ class NumericFieldTest extends SapphireTest
// Test expected formatted value // Test expected formatted value
$this->assertEquals( $this->assertEquals(
$this->clean($output), (string) $output,
$this->clean($field->Value()), $field->Value(),
"Expected $input to be formatted as $output in locale $locale" "Expected $input to be formatted as $output in locale $locale"
); );
@ -92,11 +71,11 @@ class NumericFieldTest extends SapphireTest
['nl_NL', null, '12.1', '12,1'], ['nl_NL', null, '12.1', '12,1'],
['nl_NL', 1, '14000.5', "14.000,5"], ['nl_NL', 1, '14000.5', "14.000,5"],
// fr // fr
['fr_FR', 0, '13000', "13 000"], ['fr_FR', 0, '13000', "13000"], // With a narrow non breaking space
['fr_FR', 0, '15', '15'], ['fr_FR', 0, '15', '15'],
['fr_FR', null, '12.0', '12,0'], ['fr_FR', null, '12.0', '12,0'],
['fr_FR', null, '12.1', '12,1'], ['fr_FR', null, '12.1', '12,1'],
['fr_FR', 1, '14000.5', "14 000,5"], ['fr_FR', 1, '14000.5', "14000,5"], // With a narrow non breaking space
// us // us
['en_US', 0, '13000', "13,000"], ['en_US', 0, '13000', "13,000"],
['en_US', 0, '15', '15'], ['en_US', 0, '15', '15'],
@ -172,15 +151,15 @@ class NumericFieldTest extends SapphireTest
['nl_NL', 1, '15,000.5', false], ['nl_NL', 1, '15,000.5', false],
// fr // fr
['fr_FR', 0, '13000', 13000, '13 000'], ['fr_FR', 0, '13000', 13000, '13000'], // With a narrow non breaking space
['fr_FR', 2, '12,00', 12.0], ['fr_FR', 2, '12,00', 12.0],
['fr_FR', 2, '12.00', false], ['fr_FR', 2, '12.00', false],
['fr_FR', 1, '11 000', 11000, '11 000,0'], ['fr_FR', 1, '11 000', 11000, '11000,0'], // With a narrow non breaking space
['fr_FR', 0, '11.000', 11000, '11 000'], ['fr_FR', 0, '11.000', 11000, '11000'], // With a narrow non breaking space
['fr_FR', null, '11,000', 11.000, '11,0'], ['fr_FR', null, '11,000', 11.000, '11,0'],
['fr_FR', 1, '15 000,5', 15000.5], ['fr_FR', 1, '15 000,5', 15000.5, '15000,5'], // With a narrow non breaking space
['fr_FR', 1, '15 000.5', false], ['fr_FR', 1, '15 000.5', false],
['fr_FR', 1, '15.000,5', 15000.5, '15 000,5'], ['fr_FR', 1, '15.000,5', 15000.5, '15000,5'], // With a narrow non breaking space
['fr_FR', 1, '15,000.5', false], ['fr_FR', 1, '15,000.5', false],
// us // us
['en_US', 0, '13000', 13000, '13,000'], ['en_US', 0, '13000', 13000, '13,000'],
@ -257,8 +236,8 @@ class NumericFieldTest extends SapphireTest
$cleanedInput = $submittedValue; $cleanedInput = $submittedValue;
} }
$this->assertEquals( $this->assertEquals(
$this->clean($cleanedInput), $cleanedInput,
$this->clean($field->Value()), $field->Value(),
"Expected input $submittedValue to be cleaned up as $cleanedInput in locale $locale" "Expected input $submittedValue to be cleaned up as $cleanedInput in locale $locale"
); );
} }