mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge pull request #4162 from kinglozzer/pulls/object-parse-class-spec
FIX: Object::parse_class_spec failed to parse associative arrays
This commit is contained in:
commit
c11ac5d248
140
core/Object.php
140
core/Object.php
@ -195,77 +195,113 @@ abstract class Object {
|
|||||||
$tokens = token_get_all("<?php $classSpec");
|
$tokens = token_get_all("<?php $classSpec");
|
||||||
$class = null;
|
$class = null;
|
||||||
$args = array();
|
$args = array();
|
||||||
$passedBracket = false;
|
|
||||||
|
|
||||||
// Keep track of the current bucket that we're putting data into
|
// Keep track of the current bucket that we're putting data into
|
||||||
$bucket = &$args;
|
$bucket = &$args;
|
||||||
$bucketStack = array();
|
$bucketStack = array();
|
||||||
$had_ns = false;
|
$hadNamespace = false;
|
||||||
|
$currentKey = null;
|
||||||
|
|
||||||
foreach($tokens as $token) {
|
foreach($tokens as $token) {
|
||||||
$tName = is_array($token) ? $token[0] : $token;
|
// $forceResult used to allow null result to be detected
|
||||||
// Get the class naem
|
$result = $forceResult = null;
|
||||||
if($class == null && is_array($token) && $token[0] == T_STRING) {
|
$tokenName = is_array($token) ? $token[0] : $token;
|
||||||
|
|
||||||
|
// Get the class name
|
||||||
|
if($class === null && is_array($token) && $token[0] === T_STRING) {
|
||||||
$class = $token[1];
|
$class = $token[1];
|
||||||
} elseif(is_array($token) && $token[0] == T_NS_SEPARATOR) {
|
} elseif(is_array($token) && $token[0] === T_NS_SEPARATOR) {
|
||||||
$class .= $token[1];
|
$class .= $token[1];
|
||||||
$had_ns = true;
|
$hadNamespace = true;
|
||||||
} elseif ($had_ns && is_array($token) && $token[0] == T_STRING) {
|
} elseif($hadNamespace && is_array($token) && $token[0] === T_STRING) {
|
||||||
$class .= $token[1];
|
$class .= $token[1];
|
||||||
$had_ns = false;
|
$hadNamespace = false;
|
||||||
// Get arguments
|
// Get arguments
|
||||||
} else if(is_array($token)) {
|
} else if(is_array($token)) {
|
||||||
switch($token[0]) {
|
switch($token[0]) {
|
||||||
case T_CONSTANT_ENCAPSED_STRING:
|
case T_CONSTANT_ENCAPSED_STRING:
|
||||||
$argString = $token[1];
|
$argString = $token[1];
|
||||||
switch($argString[0]) {
|
switch($argString[0]) {
|
||||||
case '"':
|
case '"':
|
||||||
$argString = stripcslashes(substr($argString,1,-1));
|
$result = stripcslashes(substr($argString,1,-1));
|
||||||
|
break;
|
||||||
|
case "'":
|
||||||
|
$result = str_replace(array("\\\\", "\\'"),array("\\", "'"), substr($argString,1,-1));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Bad T_CONSTANT_ENCAPSED_STRING arg $argString");
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case "'":
|
|
||||||
$argString = str_replace(array("\\\\", "\\'"),array("\\", "'"), substr($argString,1,-1));
|
case T_DNUMBER:
|
||||||
|
$result = (double)$token[1];
|
||||||
break;
|
break;
|
||||||
default:
|
|
||||||
throw new Exception("Bad T_CONSTANT_ENCAPSED_STRING arg $argString");
|
|
||||||
}
|
|
||||||
$bucket[] = $argString;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_DNUMBER:
|
|
||||||
$bucket[] = (double)$token[1];
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_LNUMBER:
|
case T_LNUMBER:
|
||||||
$bucket[] = (int)$token[1];
|
$result = (int)$token[1];
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case T_STRING:
|
|
||||||
switch($token[1]) {
|
|
||||||
case 'true': $bucket[] = true; break;
|
|
||||||
case 'false': $bucket[] = false; break;
|
|
||||||
case 'null': $bucket[] = null; break;
|
|
||||||
default: throw new Exception("Bad T_STRING arg '{$token[1]}'");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case T_ARRAY:
|
case T_DOUBLE_ARROW:
|
||||||
// Add an empty array to the bucket
|
// We've encountered an associative array (the array itself has already been
|
||||||
$bucket[] = array();
|
// added to the bucket), so the previous item added to the bucket is the key
|
||||||
$bucketStack[] = &$bucket;
|
end($bucket);
|
||||||
$bucket = &$bucket[sizeof($bucket)-1];
|
$currentKey = current($bucket);
|
||||||
|
array_pop($bucket);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_STRING:
|
||||||
|
switch($token[1]) {
|
||||||
|
case 'true': $result = true; break;
|
||||||
|
case 'false': $result = false; break;
|
||||||
|
case 'null': $result = null; $forceResult = true; break;
|
||||||
|
default: throw new Exception("Bad T_STRING arg '{$token[1]}'");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
case T_ARRAY:
|
||||||
|
$result = array();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if($tokenName === '[') {
|
||||||
|
$result = array();
|
||||||
|
} elseif(($tokenName === ')' || $tokenName === ']') && ! empty($bucketStack)) {
|
||||||
|
// Store the bucket we're currently working on
|
||||||
|
$oldBucket = $bucket;
|
||||||
|
// Fetch the key for the bucket at the top of the stack
|
||||||
|
end($bucketStack);
|
||||||
|
$key = key($bucketStack);
|
||||||
|
reset($bucketStack);
|
||||||
|
// Re-instate the bucket from the top of the stack
|
||||||
|
$bucket = &$bucketStack[$key];
|
||||||
|
// Add our saved, "nested" bucket to the bucket we just popped off the stack
|
||||||
|
$bucket[$key] = $oldBucket;
|
||||||
|
// Remove the bucket we just popped off the stack
|
||||||
|
array_pop($bucketStack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we've got something to add to the bucket, add it
|
||||||
|
if($result !== null || $forceResult) {
|
||||||
|
if($currentKey) {
|
||||||
|
$bucket[$currentKey] = $result;
|
||||||
|
$currentKey = null;
|
||||||
|
} else {
|
||||||
|
$bucket[] = $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
// If we've just pushed an array, that becomes our new bucket
|
||||||
if($tName == '[') {
|
if($result === array()) {
|
||||||
// Add an empty array to the bucket
|
// Fetch the key that the array was pushed to
|
||||||
$bucket[] = array();
|
end($bucket);
|
||||||
$bucketStack[] = &$bucket;
|
$key = key($bucket);
|
||||||
$bucket = &$bucket[sizeof($bucket)-1];
|
reset($bucket);
|
||||||
} elseif($tName == ')' || $tName == ']') {
|
// Store reference to "old" bucket in the stack
|
||||||
// Pop-by-reference
|
$bucketStack[$key] = &$bucket;
|
||||||
$bucket = &$bucketStack[sizeof($bucketStack)-1];
|
// Set the active bucket to be our newly-pushed, empty array
|
||||||
array_pop($bucketStack);
|
$bucket = &$bucket[$key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -417,7 +417,7 @@ class ObjectTest extends SapphireTest {
|
|||||||
// 5.4 Shorthand Array
|
// 5.4 Shorthand Array
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
array('Enum',array(array('Accepted', 'Pending', 'Declined', 'Unsubmitted'), 'Unsubmitted')),
|
array('Enum',array(array('Accepted', 'Pending', 'Declined', 'Unsubmitted'), 'Unsubmitted')),
|
||||||
Object::parse_class_spec("Enum(['Accepted', 'Pending', 'Declined', 'Unsubmitted'), 'Unsubmitted']")
|
Object::parse_class_spec("Enum(['Accepted', 'Pending', 'Declined', 'Unsubmitted'], 'Unsubmitted')")
|
||||||
);
|
);
|
||||||
// 5.4 Nested shorthand array
|
// 5.4 Nested shorthand array
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
@ -426,6 +426,28 @@ class ObjectTest extends SapphireTest {
|
|||||||
Object::parse_class_spec(
|
Object::parse_class_spec(
|
||||||
"Enum(['Accepted', 'Pending', 'Declined', ['UnsubmittedA','UnsubmittedB']], 'Unsubmitted')")
|
"Enum(['Accepted', 'Pending', 'Declined', ['UnsubmittedA','UnsubmittedB']], 'Unsubmitted')")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Associative array
|
||||||
|
$this->assertEquals(
|
||||||
|
array('Varchar', array(255, array('nullifyEmpty' => false))),
|
||||||
|
Object::parse_class_spec("Varchar(255, array('nullifyEmpty' => false))")
|
||||||
|
);
|
||||||
|
// Nested associative array
|
||||||
|
$this->assertEquals(
|
||||||
|
array('Test', array('string', array('nested' => array('foo' => 'bar')))),
|
||||||
|
Object::parse_class_spec("Test('string', array('nested' => array('foo' => 'bar')))")
|
||||||
|
);
|
||||||
|
// 5.4 shorthand associative array
|
||||||
|
$this->assertEquals(
|
||||||
|
array('Varchar', array(255, array('nullifyEmpty' => false))),
|
||||||
|
Object::parse_class_spec("Varchar(255, ['nullifyEmpty' => false])")
|
||||||
|
);
|
||||||
|
// 5.4 shorthand nested associative array
|
||||||
|
$this->assertEquals(
|
||||||
|
array('Test', array('string', array('nested' => array('foo' => 'bar')))),
|
||||||
|
Object::parse_class_spec("Test('string', ['nested' => ['foo' => 'bar']])")
|
||||||
|
);
|
||||||
|
|
||||||
// Namespaced class
|
// Namespaced class
|
||||||
$this->assertEquals(
|
$this->assertEquals(
|
||||||
array('Test\MyClass', array()),
|
array('Test\MyClass', array()),
|
||||||
|
Loading…
Reference in New Issue
Block a user