mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
ENH PHP 8.2 support
This commit is contained in:
parent
bf440e42e7
commit
c1a773310d
@ -27,7 +27,7 @@
|
|||||||
"composer/installers": "^2.2",
|
"composer/installers": "^2.2",
|
||||||
"guzzlehttp/guzzle": "^7.5.0",
|
"guzzlehttp/guzzle": "^7.5.0",
|
||||||
"guzzlehttp/psr7": "^2.4.0",
|
"guzzlehttp/psr7": "^2.4.0",
|
||||||
"embed/embed": "^4.4.4",
|
"embed/embed": "^4.4.7",
|
||||||
"league/csv": "^9.8.0",
|
"league/csv": "^9.8.0",
|
||||||
"m1/env": "^2.2.0",
|
"m1/env": "^2.2.0",
|
||||||
"monolog/monolog": "^3.2.0",
|
"monolog/monolog": "^3.2.0",
|
||||||
|
@ -579,7 +579,7 @@ class HTTPRequest implements ArrayAccess
|
|||||||
$shiftCount = sizeof($patternParts ?? []);
|
$shiftCount = sizeof($patternParts ?? []);
|
||||||
$remaining = count($this->dirParts ?? []) - $i;
|
$remaining = count($this->dirParts ?? []) - $i;
|
||||||
for ($j = 1; $j <= $remaining; $j++) {
|
for ($j = 1; $j <= $remaining; $j++) {
|
||||||
$arguments["$${j}"] = $this->dirParts[$j + $i - 1];
|
$arguments['$' . $j] = $this->dirParts[$j + $i - 1];
|
||||||
}
|
}
|
||||||
$patternParts = array_merge($patternParts, array_keys($arguments ?? []));
|
$patternParts = array_merge($patternParts, array_keys($arguments ?? []));
|
||||||
break;
|
break;
|
||||||
|
@ -20,6 +20,8 @@ class SSListContains extends Constraint implements TestOnly
|
|||||||
*/
|
*/
|
||||||
protected $matches = [];
|
protected $matches = [];
|
||||||
|
|
||||||
|
protected SSListExporter $exporter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the list has left over items that don't match
|
* Check if the list has left over items that don't match
|
||||||
*
|
*
|
||||||
|
@ -19,6 +19,8 @@ class SSListContainsOnlyMatchingItems extends Constraint implements TestOnly
|
|||||||
*/
|
*/
|
||||||
private $match;
|
private $match;
|
||||||
|
|
||||||
|
protected SSListExporter $exporter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var ViewableDataContains
|
* @var ViewableDataContains
|
||||||
*/
|
*/
|
||||||
|
@ -34,6 +34,8 @@ class FixtureBlueprint
|
|||||||
*/
|
*/
|
||||||
protected $class;
|
protected $class;
|
||||||
|
|
||||||
|
private FixtureFactory $factory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
@ -70,6 +72,17 @@ class FixtureBlueprint
|
|||||||
$this->defaults = $defaults;
|
$this->defaults = $defaults;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getFactory(): FixtureFactory
|
||||||
|
{
|
||||||
|
return $this->factory;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setFactory(FixtureFactory $factory): static
|
||||||
|
{
|
||||||
|
$this->factory = $factory;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $identifier Unique identifier for this fixture type
|
* @param string $identifier Unique identifier for this fixture type
|
||||||
* @param array $data Map of property names to their values.
|
* @param array $data Map of property names to their values.
|
||||||
|
@ -161,6 +161,8 @@ abstract class SapphireTest extends TestCase implements TestOnly
|
|||||||
*/
|
*/
|
||||||
protected static $tempDB = null;
|
protected static $tempDB = null;
|
||||||
|
|
||||||
|
protected FixtureFactory|bool $fixtureFactory;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return TempDatabase
|
* @return TempDatabase
|
||||||
*/
|
*/
|
||||||
|
@ -65,6 +65,8 @@ class MySQLDatabase extends Database implements TransactionManager
|
|||||||
*/
|
*/
|
||||||
private $transactionManager = null;
|
private $transactionManager = null;
|
||||||
|
|
||||||
|
private int $transactionNesting = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Default collation
|
* Default collation
|
||||||
*
|
*
|
||||||
|
@ -73,7 +73,6 @@ class MySQLStatement extends Query
|
|||||||
public function __destruct()
|
public function __destruct()
|
||||||
{
|
{
|
||||||
$this->statement->close();
|
$this->statement->close();
|
||||||
$this->currentRecord = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,6 +6,7 @@ use BadMethodCallException;
|
|||||||
use Exception;
|
use Exception;
|
||||||
use InvalidArgumentException;
|
use InvalidArgumentException;
|
||||||
use LogicException;
|
use LogicException;
|
||||||
|
use SilverStripe\Assets\Storage\DBFile;
|
||||||
use SilverStripe\Core\ClassInfo;
|
use SilverStripe\Core\ClassInfo;
|
||||||
use SilverStripe\Core\Config\Config;
|
use SilverStripe\Core\Config\Config;
|
||||||
use SilverStripe\Core\Injector\Injector;
|
use SilverStripe\Core\Injector\Injector;
|
||||||
@ -2841,13 +2842,21 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
// later referenced to update the parent dataobject
|
// later referenced to update the parent dataobject
|
||||||
if ($val instanceof DBComposite) {
|
if ($val instanceof DBComposite) {
|
||||||
$val->bindTo($this);
|
$val->bindTo($this);
|
||||||
$this->record[$fieldName] = $val;
|
$this->setFieldValue($fieldName, $val);
|
||||||
}
|
}
|
||||||
// Situation 2: Passing a literal or non-DBField object
|
// Situation 2: Passing a literal or non-DBField object
|
||||||
} else {
|
} else {
|
||||||
|
$this->setFieldValue($fieldName, $val);
|
||||||
|
}
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setFieldValue(string $fieldName, mixed $val): void
|
||||||
|
{
|
||||||
|
$schema = static::getSchema();
|
||||||
// If this is a proper database field, we shouldn't be getting non-DBField objects
|
// If this is a proper database field, we shouldn't be getting non-DBField objects
|
||||||
if (is_object($val) && $schema->fieldSpec(static::class, $fieldName)) {
|
if (is_object($val) && !($val instanceof DBField) && $schema->fieldSpec(static::class, $fieldName)) {
|
||||||
throw new InvalidArgumentException('DataObject::setField: passed an object that is not a DBField');
|
throw new InvalidArgumentException('DataObject::setFieldValue: passed an object that is not a DBField');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!empty($val) && !is_scalar($val)) {
|
if (!empty($val) && !is_scalar($val)) {
|
||||||
@ -2855,7 +2864,7 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
if ($dbField && $dbField->scalarValueOnly()) {
|
if ($dbField && $dbField->scalarValueOnly()) {
|
||||||
throw new InvalidArgumentException(
|
throw new InvalidArgumentException(
|
||||||
sprintf(
|
sprintf(
|
||||||
'DataObject::setField: %s only accepts scalars',
|
'DataObject::setFieldValue: %s only accepts scalars',
|
||||||
$fieldName
|
$fieldName
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
@ -2883,8 +2892,6 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity
|
|||||||
// Value is saved regardless, since the change detection relates to the last write
|
// Value is saved regardless, since the change detection relates to the last write
|
||||||
$this->record[$fieldName] = $val;
|
$this->record[$fieldName] = $val;
|
||||||
}
|
}
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the value of the field, using a casting object.
|
* Set the value of the field, using a casting object.
|
||||||
|
@ -46,7 +46,7 @@ class DBBoolean extends DBField
|
|||||||
{
|
{
|
||||||
$fieldName = $this->name;
|
$fieldName = $this->name;
|
||||||
if ($fieldName) {
|
if ($fieldName) {
|
||||||
$dataObject->$fieldName = ($this->value) ? 1 : 0;
|
$dataObject->setField($fieldName, $this->value ? 1 : 0);
|
||||||
} else {
|
} else {
|
||||||
$class = static::class;
|
$class = static::class;
|
||||||
throw new \RuntimeException("DBField::saveInto() Called on a nameless '$class' object");
|
throw new \RuntimeException("DBField::saveInto() Called on a nameless '$class' object");
|
||||||
|
@ -88,7 +88,8 @@ class DBDecimal extends DBField
|
|||||||
$fieldName = $this->name;
|
$fieldName = $this->name;
|
||||||
|
|
||||||
if ($fieldName) {
|
if ($fieldName) {
|
||||||
$dataObject->$fieldName = (float)preg_replace('/[^0-9.\-\+]/', '', $this->value ?? '');
|
$value = (float) preg_replace('/[^0-9.\-\+]/', '', $this->value ?? '');
|
||||||
|
$dataObject->setField($fieldName, $value);
|
||||||
} else {
|
} else {
|
||||||
throw new \UnexpectedValueException(
|
throw new \UnexpectedValueException(
|
||||||
"DBField::saveInto() Called on a nameless '" . static::class . "' object"
|
"DBField::saveInto() Called on a nameless '" . static::class . "' object"
|
||||||
|
@ -542,7 +542,7 @@ abstract class DBField extends ViewableData implements DBIndexable
|
|||||||
"DBField::saveInto() Called on a nameless '" . static::class . "' object"
|
"DBField::saveInto() Called on a nameless '" . static::class . "' object"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
$dataObject->$fieldName = $this->value;
|
$dataObject->setField($fieldName, $this->value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,7 +45,7 @@ class DBPercentage extends DBDecimal
|
|||||||
|
|
||||||
$fieldName = $this->name;
|
$fieldName = $this->name;
|
||||||
if ($fieldName && $dataObject->$fieldName > 1.0) {
|
if ($fieldName && $dataObject->$fieldName > 1.0) {
|
||||||
$dataObject->$fieldName = 1.0;
|
$dataObject->setField($fieldName, 1.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,6 +66,11 @@ class ViewableData implements IteratorAggregate
|
|||||||
*/
|
*/
|
||||||
private static $casting_cache = [];
|
private static $casting_cache = [];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acts as a PHP 8.2+ compliant replacement for dynamic properties
|
||||||
|
*/
|
||||||
|
private array $data = [];
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -191,7 +196,7 @@ class ViewableData implements IteratorAggregate
|
|||||||
*/
|
*/
|
||||||
public function hasField($field)
|
public function hasField($field)
|
||||||
{
|
{
|
||||||
return property_exists($this, $field ?? '');
|
return property_exists($this, $field) || isset($this->data[$field]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -202,8 +207,11 @@ class ViewableData implements IteratorAggregate
|
|||||||
*/
|
*/
|
||||||
public function getField($field)
|
public function getField($field)
|
||||||
{
|
{
|
||||||
|
if (property_exists($this, $field)) {
|
||||||
return $this->$field;
|
return $this->$field;
|
||||||
}
|
}
|
||||||
|
return $this->data[$field];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a field on this object. This should be overloaded in child classes.
|
* Set a field on this object. This should be overloaded in child classes.
|
||||||
@ -215,7 +223,13 @@ class ViewableData implements IteratorAggregate
|
|||||||
public function setField($field, $value)
|
public function setField($field, $value)
|
||||||
{
|
{
|
||||||
$this->objCacheClear();
|
$this->objCacheClear();
|
||||||
|
// prior to PHP 8.2 support ViewableData::setField() simply used `$this->field = $value;`
|
||||||
|
// so the following logic essentially mimics this behaviour, though without the use
|
||||||
|
// of now deprecated dynamic properties
|
||||||
|
if (property_exists($this, $field)) {
|
||||||
$this->$field = $value;
|
$this->$field = $value;
|
||||||
|
}
|
||||||
|
$this->data[$field] = $value;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -509,14 +523,14 @@ class ViewableData implements IteratorAggregate
|
|||||||
* A simple wrapper around {@link ViewableData::obj()} that automatically caches the result so it can be used again
|
* A simple wrapper around {@link ViewableData::obj()} that automatically caches the result so it can be used again
|
||||||
* without re-running the method.
|
* without re-running the method.
|
||||||
*
|
*
|
||||||
* @param string $field
|
* @param string $fieldName
|
||||||
* @param array $arguments
|
* @param array $arguments
|
||||||
* @param string $identifier an optional custom cache identifier
|
* @param string $identifier an optional custom cache identifier
|
||||||
* @return Object|DBField
|
* @return Object|DBField
|
||||||
*/
|
*/
|
||||||
public function cachedCall($field, $arguments = [], $identifier = null)
|
public function cachedCall($fieldName, $arguments = [], $identifier = null)
|
||||||
{
|
{
|
||||||
return $this->obj($field, $arguments, true, $identifier);
|
return $this->obj($fieldName, $arguments, true, $identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,19 +59,26 @@ class ViewableData_Customised extends ViewableData
|
|||||||
return $this->customised->hasMethod($method) || $this->original->hasMethod($method);
|
return $this->customised->hasMethod($method) || $this->original->hasMethod($method);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function cachedCall($field, $arguments = null, $identifier = null)
|
public function cachedCall($fieldName, $arguments = null, $identifier = null)
|
||||||
{
|
{
|
||||||
if ($this->customised->hasMethod($field) || $this->customised->hasField($field)) {
|
if ($this->customisedHas($fieldName)) {
|
||||||
return $this->customised->cachedCall($field, $arguments, $identifier);
|
return $this->customised->cachedCall($fieldName, $arguments, $identifier);
|
||||||
}
|
}
|
||||||
return $this->original->cachedCall($field, $arguments, $identifier);
|
return $this->original->cachedCall($fieldName, $arguments, $identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function obj($fieldName, $arguments = null, $cache = false, $cacheName = null)
|
public function obj($fieldName, $arguments = null, $cache = false, $cacheName = null)
|
||||||
{
|
{
|
||||||
if ($this->customised->hasField($fieldName) || $this->customised->hasMethod($fieldName)) {
|
if ($this->customisedHas($fieldName)) {
|
||||||
return $this->customised->obj($fieldName, $arguments, $cache, $cacheName);
|
return $this->customised->obj($fieldName, $arguments, $cache, $cacheName);
|
||||||
}
|
}
|
||||||
return $this->original->obj($fieldName, $arguments, $cache, $cacheName);
|
return $this->original->obj($fieldName, $arguments, $cache, $cacheName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function customisedHas(string $fieldName): bool
|
||||||
|
{
|
||||||
|
return property_exists($this->customised, $fieldName) ||
|
||||||
|
$this->customised->hasField($fieldName) ||
|
||||||
|
$this->customised->hasMethod($fieldName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,5 +4,7 @@ namespace SilverStripe\Core\Tests\Injector\AopProxyServiceTest;
|
|||||||
|
|
||||||
class AnotherService
|
class AnotherService
|
||||||
{
|
{
|
||||||
|
public $config_property;
|
||||||
|
|
||||||
public $filters = [];
|
public $filters = [];
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ namespace SilverStripe\Core\Tests\Injector\AopProxyServiceTest;
|
|||||||
|
|
||||||
class SampleService
|
class SampleService
|
||||||
{
|
{
|
||||||
|
public $auto;
|
||||||
public $constructorVarOne;
|
public $constructorVarOne;
|
||||||
public $constructorVarTwo;
|
public $constructorVarTwo;
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ use SilverStripe\Dev\TestOnly;
|
|||||||
|
|
||||||
class TestObject implements TestOnly
|
class TestObject implements TestOnly
|
||||||
{
|
{
|
||||||
|
public $auto;
|
||||||
|
|
||||||
public $sampleService;
|
public $sampleService;
|
||||||
|
|
||||||
|
@ -17,6 +17,8 @@ class FixtureBlueprintTest extends SapphireTest
|
|||||||
|
|
||||||
protected $usesDatabase = true;
|
protected $usesDatabase = true;
|
||||||
|
|
||||||
|
private int $_called = 0;
|
||||||
|
|
||||||
protected static $extra_dataobjects = [
|
protected static $extra_dataobjects = [
|
||||||
TestDataObject::class,
|
TestDataObject::class,
|
||||||
DataObjectRelation::class,
|
DataObjectRelation::class,
|
||||||
|
@ -138,18 +138,17 @@ class GridFieldFilterHeaderTest extends SapphireTest
|
|||||||
public function testGetSearchForm()
|
public function testGetSearchForm()
|
||||||
{
|
{
|
||||||
$searchForm = $this->component->getSearchForm($this->gridField);
|
$searchForm = $this->component->getSearchForm($this->gridField);
|
||||||
|
|
||||||
$this->assertTrue($searchForm instanceof Form);
|
$this->assertTrue($searchForm instanceof Form);
|
||||||
$this->assertEquals('Search__q', $searchForm->fields[0]->Name);
|
$fields = $searchForm->Fields()->toArray();
|
||||||
$this->assertEquals('Search__Name', $searchForm->fields[1]->Name);
|
$this->assertEquals('Search__q', $fields[0]->Name);
|
||||||
$this->assertEquals('Search__City', $searchForm->fields[2]->Name);
|
$this->assertEquals('Search__Name', $fields[1]->Name);
|
||||||
$this->assertEquals('Search__Cheerleader__Hat__Colour', $searchForm->fields[3]->Name);
|
$this->assertEquals('Search__City', $fields[2]->Name);
|
||||||
|
$this->assertEquals('Search__Cheerleader__Hat__Colour', $fields[3]->Name);
|
||||||
$this->assertEquals('TeamsSearchForm', $searchForm->Name);
|
$this->assertEquals('TeamsSearchForm', $searchForm->Name);
|
||||||
$this->assertEquals('cms-search-form', $searchForm->extraClasses['cms-search-form']);
|
$this->assertTrue($searchForm->hasExtraClass('cms-search-form'));
|
||||||
|
foreach ($fields as $field) {
|
||||||
foreach ($searchForm->fields as $field) {
|
$this->assertTrue($field->hasExtraClass('stacked'));
|
||||||
$this->assertEquals('stacked', $field->extraClasses['stacked']);
|
$this->assertTrue($field->hasExtraClass('no-change-track'));
|
||||||
$this->assertEquals('no-change-track', $field->extraClasses['no-change-track']);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -826,10 +826,6 @@ class DataObjectTest extends SapphireTest
|
|||||||
$team1->Captain = $captain2;
|
$team1->Captain = $captain2;
|
||||||
$team1->write();
|
$team1->write();
|
||||||
$this->assertEquals($captain2->ID, $team1->Captain->ID);
|
$this->assertEquals($captain2->ID, $team1->Captain->ID);
|
||||||
|
|
||||||
// Setter: Custom data (required by DataDifferencer)
|
|
||||||
$team1->Captain = DBField::create_field('HTMLFragment', '<p>No captain</p>');
|
|
||||||
$this->assertEquals('<p>No captain</p>', $team1->Captain);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -6,8 +6,9 @@ use SilverStripe\Dev\TestOnly;
|
|||||||
|
|
||||||
class NonEmptyObject implements TestOnly
|
class NonEmptyObject implements TestOnly
|
||||||
{
|
{
|
||||||
|
public $a;
|
||||||
static $c = "Cucumber";
|
public $b;
|
||||||
|
public static $c = "Cucumber";
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
|
@ -8,7 +8,7 @@ use Psr\Http\Message\StreamInterface;
|
|||||||
class MockResponse implements ResponseInterface
|
class MockResponse implements ResponseInterface
|
||||||
{
|
{
|
||||||
private EmbedUnitTest $unitTest;
|
private EmbedUnitTest $unitTest;
|
||||||
private string $firstReponse;
|
private string $firstResponse;
|
||||||
private string $secondResponse;
|
private string $secondResponse;
|
||||||
|
|
||||||
public function __construct(EmbedUnitTest $unitTest, string $firstResponse, string $secondResponse)
|
public function __construct(EmbedUnitTest $unitTest, string $firstResponse, string $secondResponse)
|
||||||
|
7
thirdparty/php-peg/Parser.php
vendored
7
thirdparty/php-peg/Parser.php
vendored
@ -9,6 +9,13 @@
|
|||||||
* the bracket if a failed match + restore has moved the current position backwards - so we have to check that too.
|
* the bracket if a failed match + restore has moved the current position backwards - so we have to check that too.
|
||||||
*/
|
*/
|
||||||
class ParserRegexp {
|
class ParserRegexp {
|
||||||
|
|
||||||
|
public $parser;
|
||||||
|
public $rx;
|
||||||
|
public $matches;
|
||||||
|
public $match_pos;
|
||||||
|
public $check_pos;
|
||||||
|
|
||||||
function __construct( $parser, $rx ) {
|
function __construct( $parser, $rx ) {
|
||||||
$this->parser = $parser ;
|
$this->parser = $parser ;
|
||||||
$this->rx = $rx . 'Sx' ;
|
$this->rx = $rx . 'Sx' ;
|
||||||
|
Loading…
Reference in New Issue
Block a user