NEW: PHP 7 compatibility

This patch introduces PHP 7 compatability without breaking semver by adding DBInt
and DBFloat classes, with Int/Float classes that are only loaded into PHP 5 environments
This commit is contained in:
Loz Calver 2017-04-03 21:05:25 +01:00 committed by Sam Minnee
parent 51f98c973f
commit 40bf945322
20 changed files with 82 additions and 29 deletions

View File

@ -17,11 +17,15 @@ matrix:
env: DB=SQLITE env: DB=SQLITE
- php: 5.6 - php: 5.6
env: DB=MYSQL PDO=1 env: DB=MYSQL PDO=1
- php: 7.0
env: DB=MYSQL
- php: 7.1
env: DB=MYSQL PDO=1
- php: 5.6 - php: 5.6
env: DB=MYSQL BEHAT_TEST=1 env: DB=MYSQL BEHAT_TEST=1
- php: 5.6 - php: 7.0
env: DB=MYSQL CMS_TEST=1 env: DB=MYSQL CMS_TEST=1
- php: 5.6 - php: 7.0
env: DB=MYSQL BEHAT_TEST=1 CMS_TEST=1 env: DB=MYSQL BEHAT_TEST=1 CMS_TEST=1
before_script: before_script:

View File

@ -20,3 +20,7 @@ Injector:
PDOConnector: PDOConnector:
class: 'PDOConnector' class: 'PDOConnector'
type: prototype type: prototype
Int:
class: DBInt
Float:
class: DBFloat

View File

@ -16,7 +16,7 @@
} }
], ],
"require": { "require": {
"php": ">=5.3.3,<7", "php": ">= 5.3.3, <7.2",
"composer/installers": "~1.0" "composer/installers": "~1.0"
}, },
"require-dev": { "require-dev": {

View File

@ -112,6 +112,9 @@ if(file_exists(BASE_PATH . '/vendor/autoload.php')) {
require_once BASE_PATH . '/vendor/autoload.php'; require_once BASE_PATH . '/vendor/autoload.php';
} }
// Int/Float autoloader for PHP5.6 backwards-compatability
require_once(BASE_PATH . '/framework/model/fieldtypes/compat/autoload.php');
// Now that the class manifest is up, load the static configuration // Now that the class manifest is up, load the static configuration
$configManifest = new SS_ConfigStaticManifest(BASE_PATH, false, $flush); $configManifest = new SS_ConfigStaticManifest(BASE_PATH, false, $flush);
Config::inst()->pushConfigStaticManifest($configManifest); Config::inst()->pushConfigStaticManifest($configManifest);

View File

@ -14,12 +14,7 @@
// You may copy this code freely under the conditions of the GPL. // You may copy this code freely under the conditions of the GPL.
// //
// FIXME: possibly remove assert()'s for production version? define('USE_ASSERTS', true);
// PHP3 does not have assert()
/**
*/
define('USE_ASSERTS', function_exists('assert'));
/** /**
* @package framework * @package framework
@ -52,7 +47,7 @@ class _DiffOp {
class _DiffOp_Copy extends _DiffOp { class _DiffOp_Copy extends _DiffOp {
var $type = 'copy'; var $type = 'copy';
public function _DiffOp_Copy ($orig, $final = false) { public function __construct ($orig, $final = false) {
if (!is_array($final)) if (!is_array($final))
$final = $orig; $final = $orig;
$this->orig = $orig; $this->orig = $orig;
@ -72,7 +67,7 @@ class _DiffOp_Copy extends _DiffOp {
class _DiffOp_Delete extends _DiffOp { class _DiffOp_Delete extends _DiffOp {
var $type = 'delete'; var $type = 'delete';
public function _DiffOp_Delete ($lines) { public function __construct ($lines) {
$this->orig = $lines; $this->orig = $lines;
$this->final = false; $this->final = false;
} }
@ -90,7 +85,7 @@ class _DiffOp_Delete extends _DiffOp {
class _DiffOp_Add extends _DiffOp { class _DiffOp_Add extends _DiffOp {
var $type = 'add'; var $type = 'add';
public function _DiffOp_Add ($lines) { public function __construct ($lines) {
$this->final = $lines; $this->final = $lines;
$this->orig = false; $this->orig = false;
} }
@ -108,7 +103,7 @@ class _DiffOp_Add extends _DiffOp {
class _DiffOp_Change extends _DiffOp { class _DiffOp_Change extends _DiffOp {
var $type = 'change'; var $type = 'change';
public function _DiffOp_Change ($orig, $final) { public function __construct ($orig, $final) {
$this->orig = $orig; $this->orig = $orig;
$this->final = $final; $this->final = $final;
} }
@ -541,7 +536,7 @@ class Diff
* (Typically these are lines from a file.) * (Typically these are lines from a file.)
* @param $to_lines array An array of strings. * @param $to_lines array An array of strings.
*/ */
public function Diff($from_lines, $to_lines) { public function __construct($from_lines, $to_lines) {
$eng = new _DiffEngine; $eng = new _DiffEngine;
$this->edits = $eng->diff($from_lines, $to_lines); $this->edits = $eng->diff($from_lines, $to_lines);
//$this->_check($from_lines, $to_lines); //$this->_check($from_lines, $to_lines);
@ -853,13 +848,13 @@ extends Diff
* @param $mapped_to_lines array This array should * @param $mapped_to_lines array This array should
* have the same number of elements as $to_lines. * have the same number of elements as $to_lines.
*/ */
public function MappedDiff($from_lines, $to_lines, public function __construct($from_lines, $to_lines,
$mapped_from_lines, $mapped_to_lines) { $mapped_from_lines, $mapped_to_lines) {
assert(sizeof($from_lines) == sizeof($mapped_from_lines)); assert(sizeof($from_lines) == sizeof($mapped_from_lines));
assert(sizeof($to_lines) == sizeof($mapped_to_lines)); assert(sizeof($to_lines) == sizeof($mapped_to_lines));
$this->Diff($mapped_from_lines, $mapped_to_lines); parent::__construct($mapped_from_lines, $mapped_to_lines);
$xi = $yi = 0; $xi = $yi = 0;
// Optimizing loop invariants: // Optimizing loop invariants:

View File

@ -578,7 +578,7 @@ abstract class DBSchemaManager {
$spec['parts']['name'] = $field; $spec['parts']['name'] = $field;
$spec_orig['parts']['name'] = $field; $spec_orig['parts']['name'] = $field;
//Convert the $spec array into a database-specific string //Convert the $spec array into a database-specific string
$spec = $this->$spec['type']($spec['parts'], true); $spec = $this->{$spec['type']}($spec['parts'], true);
} }
// Collations didn't come in until MySQL 4.1. Anything earlier will throw a syntax error if you try and use // Collations didn't come in until MySQL 4.1. Anything earlier will throw a syntax error if you try and use
@ -615,7 +615,7 @@ abstract class DBSchemaManager {
// Get the version of the field as we would create it. This is used for comparison purposes to see if the // Get the version of the field as we would create it. This is used for comparison purposes to see if the
// existing field is different to what we now want // existing field is different to what we now want
if (is_array($spec_orig)) { if (is_array($spec_orig)) {
$spec_orig = $this->$spec_orig['type']($spec_orig['parts']); $spec_orig = $this->{$spec_orig['type']}($spec_orig['parts']);
} }
if ($newTable || $fieldValue == '') { if ($newTable || $fieldValue == '') {

View File

@ -8,7 +8,7 @@
* @subpackage model * @subpackage model
* @see Int * @see Int
*/ */
class BigInt extends Int { class BigInt extends DBInt {
public function requireField() { public function requireField() {
$parts = array( $parts = array(

View File

@ -5,7 +5,7 @@
* @package framework * @package framework
* @subpackage model * @subpackage model
*/ */
class Float extends DBField { class DBFloat extends DBField {
public function __construct($name = null, $defaultVal = 0) { public function __construct($name = null, $defaultVal = 0) {
$this->defaultVal = is_float($defaultVal) ? $defaultVal : (float) 0; $this->defaultVal = is_float($defaultVal) ? $defaultVal : (float) 0;

View File

@ -5,7 +5,7 @@
* @package framework * @package framework
* @subpackage model * @subpackage model
*/ */
class Int extends DBField { class DBInt extends DBField {
public function __construct($name = null, $defaultVal = 0) { public function __construct($name = null, $defaultVal = 0) {
$this->defaultVal = is_int($defaultVal) ? $defaultVal : 0; $this->defaultVal = is_int($defaultVal) ? $defaultVal : 0;
@ -63,4 +63,3 @@ class Int extends DBField {
} }
} }

View File

@ -4,7 +4,7 @@
* @package framework * @package framework
* @subpackage model * @subpackage model
*/ */
class Double extends Float { class Double extends DBFloat {
public function requireField() { public function requireField() {
// HACK: MSSQL does not support double so we're using float instead // HACK: MSSQL does not support double so we're using float instead

View File

@ -12,7 +12,7 @@
* @package framework * @package framework
* @subpackage model * @subpackage model
*/ */
class ForeignKey extends Int { class ForeignKey extends DBInt {
/** /**
* @var DataObject * @var DataObject

View File

@ -7,7 +7,7 @@
* @package framework * @package framework
* @subpackage model * @subpackage model
*/ */
class PrimaryKey extends Int { class PrimaryKey extends DBInt {
/** /**
* @var DataObject * @var DataObject
*/ */

View File

@ -0,0 +1,6 @@
<?php
class Float extends DBFloat
{
}

View File

@ -0,0 +1,6 @@
<?php
class Int extends DBInt
{
}

View File

@ -0,0 +1,17 @@
<?php
if (PHP_MAJOR_VERSION < 7) {
spl_autoload_register('php5_compat_autoloader');
}
function php5_compat_autoloader($classname) {
$classMap = array(
"int" => "/framework/model/fieldtypes/compat/Int.php",
"float" => "/framework/model/fieldtypes/compat/Float.php",
);
$classname = strtolower($classname);
if(isset($classMap[$classname])) {
require_once BASE_PATH . $classMap[$classname];
}
}

View File

@ -229,6 +229,25 @@ class DBFieldTest extends SapphireTest {
$this->assertEquals('åäö', DBField::create_field('Text', 'ÅÄÖ')->LowerCase()); $this->assertEquals('åäö', DBField::create_field('Text', 'ÅÄÖ')->LowerCase());
} }
public function testIntFloatPhp5Behaviour() {
if (PHP_MAJOR_VERSION < 7) {
// PHP 5 - Int class exists and is an instance of DBInt
// Can't use the reserved words for these classes or we'll get a compile error on PHP7
$classname = "int";
$obj = new $classname();
$this->assertInstanceOf('DBInt', $obj);
$classname = "float";
$obj = new $classname();
$this->assertInstanceOf('DBFloat', $obj);
} else {
// PHP 7 - classes don't exist
$this->assertFalse(class_exists("Int"));
$this->assertFalse(class_exists("Float"));
}
}
} }

View File

@ -180,11 +180,11 @@ class VersionedTest extends SapphireTest {
public function testVersionedFieldsAdded() { public function testVersionedFieldsAdded() {
$obj = new VersionedTest_DataObject(); $obj = new VersionedTest_DataObject();
// Check that the Version column is added as a full-fledged column // Check that the Version column is added as a full-fledged column
$this->assertInstanceOf('Int', $obj->dbObject('Version')); $this->assertInstanceOf('DBInt', $obj->dbObject('Version'));
$obj2 = new VersionedTest_Subclass(); $obj2 = new VersionedTest_Subclass();
// Check that the Version column is added as a full-fledged column // Check that the Version column is added as a full-fledged column
$this->assertInstanceOf('Int', $obj2->dbObject('Version')); $this->assertInstanceOf('DBInt', $obj2->dbObject('Version'));
} }
public function testVersionedFieldsNotInCMS() { public function testVersionedFieldsNotInCMS() {

View File

@ -536,7 +536,7 @@ class SSViewer_DataPresenter extends SSViewer_Scope {
// If not provided, use default // If not provided, use default
if (!$casting) $casting = Config::inst()->get('ViewableData', 'default_cast', Config::FIRST_SET); if (!$casting) $casting = Config::inst()->get('ViewableData', 'default_cast', Config::FIRST_SET);
$obj = new $casting($property); $obj = Injector::inst()->create($casting, false, array($property));
$obj->setValue($res['value']); $obj->setValue($res['value']);
$res['obj'] = $obj; $res['obj'] = $obj;

View File

@ -331,7 +331,7 @@ class ViewableData extends Object implements IteratorAggregate {
public function escapeTypeForField($field) { public function escapeTypeForField($field) {
$class = $this->castingClass($field) ?: $this->config()->default_cast; $class = $this->castingClass($field) ?: $this->config()->default_cast;
return Config::inst()->get($class, 'escape_type', Config::FIRST_SET); return Injector::inst()->get($class, true)->config()->escape_type;
} }
/** /**