Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PHP 8 support #9665

Merged
merged 15 commits into from
Sep 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ matrix:
- DB=PGSQL
- PHPCS_TEST=1
- PHPUNIT_TEST=framework
- COMPOSER_INSTALL_ARG="--prefer-lowest"

- php: 7.2
env:
Expand All @@ -49,6 +50,16 @@ matrix:
packages:
- libonig-dev

- php: nightly
env:
- DB=MYSQL
- PHPUNIT_TEST=framework
- COMPOSER_INSTALL_ARG="--ignore-platform-reqs"
addons:
apt:
packages:
- libonig-dev

- php: 7.3
if: type IN (cron)
env:
Expand Down Expand Up @@ -78,7 +89,7 @@ before_script:
- composer require silverstripe/recipe-testing:^1 silverstripe/recipe-core:4.x-dev silverstripe/admin:1.x-dev silverstripe/versioned:1.x-dev --no-update
- if [[ $PHPUNIT_TEST == cms ]]; then composer require silverstripe/recipe-cms:4.x-dev --no-update; fi
- if [[ $PHPCS_TEST ]]; then composer global require squizlabs/php_codesniffer:^3 --prefer-dist --no-interaction --no-progress --no-suggest -o; fi
- composer install --prefer-source --no-interaction --no-progress --no-suggest --optimize-autoloader --verbose --profile
- composer update --prefer-source --no-interaction --no-progress --no-suggest --optimize-autoloader --verbose --profile $COMPOSER_INSTALL_ARG
dhensby marked this conversation as resolved.
Show resolved Hide resolved

# Log constants to CI for debugging purposes
- php ./tests/dump_constants.php
Expand Down
10 changes: 5 additions & 5 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,11 @@
"bramus/monolog-colored-line-formatter": "~2.0",
"composer/installers": "~1.0",
"embed/embed": "^3.0",
"league/csv": "^8",
"league/csv": "^8 || ^9",
"league/flysystem": "~1.0.12",
"m1/env": "^2.1",
"monolog/monolog": "~1.11",
"nikic/php-parser": "^2 || ^3 || ^4",
"monolog/monolog": "~1.16",
"nikic/php-parser": "^3 || ^4",
"psr/container": "1.0.0",
"psr/container-implementation": "1.0.0",
"silverstripe/config": "^1@dev",
Expand All @@ -53,8 +53,8 @@
"ext-xml": "*"
},
"require-dev": {
"phpunit/phpunit": "^5.7",
"sminnee/phpunit-mock-objects": "^3.4.5",
"sminnee/phpunit": "^5.7.29",
"sminnee/phpunit-mock-objects": "^3.4.9",
"silverstripe/versioned": "^1",
"squizlabs/php_codesniffer": "^3.5"
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public function addMethods(...$methods)
// uppercase and exclude empties
$methods = array_reduce(
$methods,
static function &(&$result, $method) {
function ($result, $method) {
$method = strtoupper(trim($method));
if (strlen($method)) {
$result[] = $method;
Expand Down
8 changes: 7 additions & 1 deletion src/Core/ClassInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,13 @@ public static function parse_class_spec($classSpec)
$tokenName = is_array($token) ? $token[0] : $token;

// Get the class name
if ($class === null && is_array($token) && $token[0] === T_STRING) {
if (\defined('T_NAME_QUALIFIED') && is_array($token) &&
($token[0] === T_NAME_QUALIFIED || $token[0] === T_NAME_FULLY_QUALIFIED)
) {
// PHP 8 exposes the FQCN as a single T_NAME_QUALIFIED or T_NAME_FULLY_QUALIFIED token
$class .= $token[1];
$hadNamespace = true;
} elseif ($class === null && is_array($token) && $token[0] === T_STRING) {
$class = $token[1];
} elseif (is_array($token) && $token[0] === T_NS_SEPARATOR) {
$class .= $token[1];
Expand Down
4 changes: 2 additions & 2 deletions src/Core/Config/Middleware/InheritanceMiddleware.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ public function getClassConfig($class, $excludeMiddleware, $next)
return $config;
}

// Skip if no parent class
$parent = get_parent_class($class);
// Skip if not a class or not parent class
$parent = class_exists($class) ? get_parent_class($class) : null;
if (!$parent) {
return $config;
}
Expand Down
7 changes: 6 additions & 1 deletion src/Core/Convert.php
Original file line number Diff line number Diff line change
Expand Up @@ -296,12 +296,17 @@ public static function json2array($val)
* @param string $val
* @param boolean $disableDoctypes Disables the use of DOCTYPE, and will trigger an error if encountered.
* false by default.
* @param boolean $disableExternals Disables the loading of external entities. false by default.
* @param boolean $disableExternals Disables the loading of external entities. false by default. No-op in PHP 8.
* @return array
* @throws Exception
*/
public static function xml2array($val, $disableDoctypes = false, $disableExternals = false)
{
// PHP 8 deprecates libxml_disable_entity_loader() as it is no longer needed
if (\PHP_VERSION_ID >= 80000) {
$disableExternals = false;
}

// Check doctype
if ($disableDoctypes && preg_match('/\<\!DOCTYPE.+]\>/', $val)) {
throw new InvalidArgumentException('XML Doctype parsing disabled');
Expand Down
2 changes: 2 additions & 0 deletions src/Core/Injector/InjectionCreator.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ public function create($class, array $params = [])
}

if (count($params)) {
// Remove named keys to ensure that PHP7 and PHP8 interpret these the same way
$params = array_values($params);
return $reflector->newInstanceArgs($params);
}

Expand Down
1 change: 1 addition & 0 deletions src/Core/Injector/InjectorNotFoundException.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace SilverStripe\Core\Injector;

use Psr\Container\NotFoundExceptionInterface;
use Throwable;
dhensby marked this conversation as resolved.
Show resolved Hide resolved

class InjectorNotFoundException extends \Exception implements NotFoundExceptionInterface
{
Expand Down
30 changes: 24 additions & 6 deletions src/Dev/CsvBulkLoader.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace SilverStripe\Dev;

use League\Csv\MapIterator;
use League\Csv\Reader;
use SilverStripe\Control\Director;
use SilverStripe\ORM\DataObject;
Expand Down Expand Up @@ -76,9 +77,16 @@ protected function processAll($filepath, $preview = false)
$filepath = Director::getAbsFile($filepath);
$csvReader = Reader::createFromPath($filepath, 'r');
$csvReader->setDelimiter($this->delimiter);
$csvReader->stripBom(true);

$tabExtractor = function ($row, $rowOffset, $iterator) {
// league/csv 9
if (method_exists($csvReader, 'skipInputBOM')) {
$csvReader->skipInputBOM();
// league/csv 8
} else {
$csvReader->stripBom(true);
}

$tabExtractor = function ($row, $rowOffset) {
foreach ($row as &$item) {
// [SS-2017-007] Ensure all cells with leading tab and then [@=+] have the tab removed on import
if (preg_match("/^\t[\-@=\+]+.*/", $item)) {
Expand All @@ -90,8 +98,9 @@ protected function processAll($filepath, $preview = false)

if ($this->columnMap) {
$headerMap = $this->getNormalisedColumnMap();
$remapper = function ($row, $rowOffset, $iterator) use ($headerMap, $tabExtractor) {
$row = $tabExtractor($row, $rowOffset, $iterator);

$remapper = function ($row, $rowOffset) use ($headerMap, $tabExtractor) {
$row = $tabExtractor($row, $rowOffset);
foreach ($headerMap as $column => $renamedColumn) {
if ($column == $renamedColumn) {
continue;
Expand All @@ -110,9 +119,18 @@ protected function processAll($filepath, $preview = false)
}

if ($this->hasHeaderRow) {
$rows = $csvReader->fetchAssoc(0, $remapper);
if (method_exists($csvReader, 'fetchAssoc')) {
$rows = $csvReader->fetchAssoc(0, $remapper);
} else {
$csvReader->setHeaderOffset(0);
$rows = new MapIterator($csvReader->getRecords(), $remapper);
}
} elseif ($this->columnMap) {
$rows = $csvReader->fetchAssoc($headerMap, $remapper);
if (method_exists($csvReader, 'fetchAssoc')) {
$rows = $csvReader->fetchAssoc($headerMap, $remapper);
} else {
$rows = new MapIterator($csvReader->getRecords($headerMap), $remapper);
}
}

foreach ($rows as $row) {
Expand Down
4 changes: 4 additions & 0 deletions src/Forms/GridField/GridFieldExportButton.php
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,10 @@ public function generateExportFileData($gridField)
}
}

if (method_exists($csvWriter, 'getContent')) {
return $csvWriter->getContent();
}

return (string)$csvWriter;
}

Expand Down
4 changes: 2 additions & 2 deletions src/ORM/DataQueryManipulator.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ interface DataQueryManipulator
* @param array $queriedColumns
* @param SQLSelect $sqlSelect
*/
public function beforeGetFinalisedQuery(DataQuery $dataQuery, $queriedColumns = [], SQLSelect $sqlSelect);
public function beforeGetFinalisedQuery(DataQuery $dataQuery, $queriedColumns, SQLSelect $sqlSelect);

/**
* Invoked after getFinalisedQuery()
Expand All @@ -25,5 +25,5 @@ public function beforeGetFinalisedQuery(DataQuery $dataQuery, $queriedColumns =
* @param array $queriedColumns
* @param SQLSelect $sqlQuery
*/
public function afterGetFinalisedQuery(DataQuery $dataQuery, $queriedColumns = [], SQLSelect $sqlQuery);
public function afterGetFinalisedQuery(DataQuery $dataQuery, $queriedColumns, SQLSelect $sqlQuery);
}
4 changes: 2 additions & 2 deletions src/ORM/ManyManyThroughQueryManipulator.php
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ public function getJoinAlias()
* @param array $queriedColumns
* @param SQLSelect $sqlSelect
*/
public function beforeGetFinalisedQuery(DataQuery $dataQuery, $queriedColumns = [], SQLSelect $sqlSelect)
public function beforeGetFinalisedQuery(DataQuery $dataQuery, $queriedColumns, SQLSelect $sqlSelect)
{
// Get metadata and SQL from join table
$hasManyRelation = $this->getParentRelationship($dataQuery);
Expand Down Expand Up @@ -281,7 +281,7 @@ public function beforeGetFinalisedQuery(DataQuery $dataQuery, $queriedColumns =
* @param array $queriedColumns
* @param SQLSelect $sqlQuery
*/
public function afterGetFinalisedQuery(DataQuery $dataQuery, $queriedColumns = [], SQLSelect $sqlQuery)
public function afterGetFinalisedQuery(DataQuery $dataQuery, $queriedColumns, SQLSelect $sqlQuery)
{
// Inject final replacement after manipulation has been performed on the base dataquery
$joinTableSQL = $dataQuery->getQueryParam('Foreign.JoinTableSQL');
Expand Down
3 changes: 2 additions & 1 deletion src/Security/PasswordEncryptor.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ public static function create_for_algorithm($algorithm)
return new $class;
}

$arguments = $encryptors[$algorithm];
// Don't treat array keys as argument names - keeps PHP 7 and PHP 8 operating similarly
$arguments = array_values($encryptors[$algorithm]);
return($refClass->newInstanceArgs($arguments));
}

Expand Down
2 changes: 1 addition & 1 deletion src/View/Embed/EmbedResource.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class EmbedResource implements Embeddable
/**
* @var array
*/
protected $options;
protected $options = [];

/**
* @var DispatcherInterface
Expand Down
7 changes: 7 additions & 0 deletions src/i18n/TextCollection/i18nTextCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,13 @@ public function collectFromCode($content, $fileName, Module $module)
if (is_array($token)) {
list($id, $text) = $token;

// PHP 8 namespace tokens
if (\defined('T_NAME_QUALIFIED') && in_array($id, [T_NAME_FULLY_QUALIFIED, T_NAME_QUALIFIED])) {
$inNamespace = true;
$currentClass[] = $text;
continue;
}

// Check class
if ($id === T_NAMESPACE) {
$inNamespace = true;
Expand Down
2 changes: 1 addition & 1 deletion tests/php/Core/ClassInfoTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,7 @@ public function testClassName()
public function testNonClassName()
{
$this->expectException(ReflectionException::class);
$this->expectExceptionMessage('Class IAmAClassThatDoesNotExist does not exist');
$this->expectExceptionMessageRegExp('/Class "?IAmAClassThatDoesNotExist"? does not exist/');
$this->assertEquals('IAmAClassThatDoesNotExist', ClassInfo::class_name('IAmAClassThatDoesNotExist'));
}

Expand Down
40 changes: 20 additions & 20 deletions tests/php/Dev/SapphireTestTest/DataProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,34 +42,34 @@ public static function provideEqualListsWithEmptyList()
public static function provideEqualLists()
{
return [
[
'oneParameterOneItem' => [
'oneParameterOneItem' => [
Cheddam marked this conversation as resolved.
Show resolved Hide resolved
[
['FirstName' => 'Ingo'],
],
self::$oneItemList,
],
[
'twoParametersOneItem' => [
'twoParametersOneItem' => [
[
['FirstName' => 'Ingo', 'Surname' => 'Schommer'],
],
self::$oneItemList,
],
[
'oneParameterTwoItems' => [
'oneParameterTwoItems' => [
[
['FirstName' => 'Ingo'],
['FirstName' => 'Sam'],
],
self::$twoItemList,
],
[
'twoParametersTwoItems' => [
'twoParametersTwoItems' => [
[
['FirstName' => 'Ingo', 'Surname' => 'Schommer'],
['FirstName' => 'Sam', 'Surname' => 'Minnee'],
],
self::$twoItemList,
],
[
'mixedParametersTwoItems' => [
'mixedParametersTwoItems' => [
[
['FirstName' => 'Ingo', 'Surname' => 'Schommer'],
['FirstName' => 'Sam'],
],
Expand All @@ -85,34 +85,34 @@ public static function provideNonEqualLists()
{

return [
[
'checkAgainstEmptyList' => [
'checkAgainstEmptyList' => [
[
['FirstName' => 'Ingo'],
],
[],
],
[
'oneItemExpectedListContainsMore' => [
'oneItemExpectedListContainsMore' => [
[
['FirstName' => 'Ingo'],
],
self::$twoItemList,
],
[
'oneExpectationHasWrontParamter' => [
'oneExpectationHasWrontParamter' => [
[
['FirstName' => 'IngoXX'],
['FirstName' => 'Sam'],
],
self::$twoItemList,
],
[
'differentParametersInDifferentItemsAreWrong' => [
'differentParametersInDifferentItemsAreWrong' => [
[
['FirstName' => 'IngoXXX', 'Surname' => 'Schommer'],
['FirstName' => 'Sam', 'Surname' => 'MinneeXXX'],
],
self::$twoItemList,
],
[
'differentParametersNotMatching' => [
'differentParametersNotMatching' => [
[
['FirstName' => 'Daniel', 'Surname' => 'Foo'],
['FirstName' => 'Dan'],
],
Expand Down
Loading