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
- php: 5.6
env: DB=MYSQL PDO=1
- php: 7.0
env: DB=MYSQL
- php: 7.1
env: DB=MYSQL PDO=1
- php: 5.6
env: DB=MYSQL BEHAT_TEST=1
- php: 5.6
- php: 7.0
env: DB=MYSQL CMS_TEST=1
- php: 5.6
- php: 7.0
env: DB=MYSQL BEHAT_TEST=1 CMS_TEST=1
before_script:

View File

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

View File

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

View File

@ -112,6 +112,9 @@ if(file_exists(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
$configManifest = new SS_ConfigStaticManifest(BASE_PATH, false, $flush);
Config::inst()->pushConfigStaticManifest($configManifest);

View File

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

View File

@ -578,7 +578,7 @@ abstract class DBSchemaManager {
$spec['parts']['name'] = $field;
$spec_orig['parts']['name'] = $field;
//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
@ -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
// existing field is different to what we now want
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 == '') {

View File

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

View File

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

View File

@ -5,7 +5,7 @@
* @package framework
* @subpackage model
*/
class Int extends DBField {
class DBInt extends DBField {
public function __construct($name = null, $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
* @subpackage model
*/
class Double extends Float {
class Double extends DBFloat {
public function requireField() {
// HACK: MSSQL does not support double so we're using float instead

View File

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

View File

@ -7,7 +7,7 @@
* @package framework
* @subpackage model
*/
class PrimaryKey extends Int {
class PrimaryKey extends DBInt {
/**
* @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());
}
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() {
$obj = new VersionedTest_DataObject();
// 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();
// 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() {

View File

@ -536,7 +536,7 @@ class SSViewer_DataPresenter extends SSViewer_Scope {
// If not provided, use default
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']);
$res['obj'] = $obj;

View File

@ -331,7 +331,7 @@ class ViewableData extends Object implements IteratorAggregate {
public function escapeTypeForField($field) {
$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;
}
/**