mirror of
https://github.com/silverstripe/silverstripe-framework
synced 2024-10-22 14:05:37 +02:00
Merge remote-tracking branch 'origin/3.0' into 3.1
Conflicts: admin/javascript/LeftAndMain.AddForm.js control/Director.php control/HTTPResponse.php dev/Profiler.php email/Mailer.php forms/ComplexTableField.php forms/ManyManyComplexTableField.php forms/SimpleImageField.php forms/TableField.php forms/TableListField.php javascript/ComplexTableField.js javascript/ImageFormAction.js javascript/TableField.js javascript/TableListField.js security/Member.php tests/behat/features/bootstrap/SilverStripe/Framework/Test/Behaviour/CmsUiContext.php tests/forms/TableListFieldTest.php
This commit is contained in:
commit
f03ad7b0dd
@ -362,6 +362,7 @@ class Injector {
|
|||||||
// EXCEPT when there's already an existing instance at this id.
|
// EXCEPT when there's already an existing instance at this id.
|
||||||
// if so, we need to instantiate and replace immediately
|
// if so, we need to instantiate and replace immediately
|
||||||
if (isset($this->serviceCache[$id])) {
|
if (isset($this->serviceCache[$id])) {
|
||||||
|
$this->updateSpecConstructor($spec);
|
||||||
$this->instantiate($spec, $id);
|
$this->instantiate($spec, $id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -404,6 +405,20 @@ class Injector {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a class specification to convert constructor configuration information if needed
|
||||||
|
*
|
||||||
|
* We do this as a separate process to avoid unneeded calls to convertServiceProperty
|
||||||
|
*
|
||||||
|
* @param array $spec
|
||||||
|
* The class specification to update
|
||||||
|
*/
|
||||||
|
protected function updateSpecConstructor(&$spec) {
|
||||||
|
if (isset($spec['constructor'])) {
|
||||||
|
$spec['constructor'] = $this->convertServiceProperty($spec['constructor']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Recursively convert a value into its proper representation with service references
|
* Recursively convert a value into its proper representation with service references
|
||||||
* resolved to actual objects
|
* resolved to actual objects
|
||||||
@ -468,7 +483,7 @@ class Injector {
|
|||||||
$constructorParams = $spec['constructor'];
|
$constructorParams = $spec['constructor'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$object = $this->objectCreator->create($this, $class, $constructorParams);
|
$object = $this->objectCreator->create($class, $constructorParams);
|
||||||
|
|
||||||
// figure out if we have a specific id set or not. In some cases, we might be instantiating objects
|
// figure out if we have a specific id set or not. In some cases, we might be instantiating objects
|
||||||
// that we don't manage directly; we don't want to store these in the service cache below
|
// that we don't manage directly; we don't want to store these in the service cache below
|
||||||
@ -735,10 +750,17 @@ class Injector {
|
|||||||
if (($type && $type == 'prototype') || !$asSingleton) {
|
if (($type && $type == 'prototype') || !$asSingleton) {
|
||||||
if ($spec && $constructorArgs) {
|
if ($spec && $constructorArgs) {
|
||||||
$spec['constructor'] = $constructorArgs;
|
$spec['constructor'] = $constructorArgs;
|
||||||
|
} else {
|
||||||
|
// convert any _configured_ constructor args.
|
||||||
|
// we don't call this for get() calls where someone passes in
|
||||||
|
// constructor args, otherwise we end up calling convertServiceParams
|
||||||
|
// way too often
|
||||||
|
$this->updateSpecConstructor($spec);
|
||||||
}
|
}
|
||||||
return $this->instantiate($spec, $serviceName, !$type ? 'prototype' : $type);
|
return $this->instantiate($spec, $serviceName, !$type ? 'prototype' : $type);
|
||||||
} else {
|
} else {
|
||||||
if (!isset($this->serviceCache[$serviceName])) {
|
if (!isset($this->serviceCache[$serviceName])) {
|
||||||
|
$this->updateSpecConstructor($spec);
|
||||||
$this->instantiate($spec, $serviceName);
|
$this->instantiate($spec, $serviceName);
|
||||||
}
|
}
|
||||||
return $this->serviceCache[$serviceName];
|
return $this->serviceCache[$serviceName];
|
||||||
@ -750,6 +772,7 @@ class Injector {
|
|||||||
$this->load(array($name => $config));
|
$this->load(array($name => $config));
|
||||||
if (isset($this->specs[$name])) {
|
if (isset($this->specs[$name])) {
|
||||||
$spec = $this->specs[$name];
|
$spec = $this->specs[$name];
|
||||||
|
$this->updateSpecConstructor($spec);
|
||||||
return $this->instantiate($spec, $name);
|
return $this->instantiate($spec, $name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -816,10 +839,10 @@ class InjectionCreator {
|
|||||||
* @param array $params
|
* @param array $params
|
||||||
* An array of parameters to be passed to the constructor
|
* An array of parameters to be passed to the constructor
|
||||||
*/
|
*/
|
||||||
public function create(Injector $injector, $class, $params = array()) {
|
public function create($class, $params = array()) {
|
||||||
$reflector = new ReflectionClass($class);
|
$reflector = new ReflectionClass($class);
|
||||||
if (count($params)) {
|
if (count($params)) {
|
||||||
return $reflector->newInstanceArgs($injector->convertServiceProperty($params));
|
return $reflector->newInstanceArgs($params);
|
||||||
}
|
}
|
||||||
return $reflector->newInstance();
|
return $reflector->newInstance();
|
||||||
}
|
}
|
||||||
@ -833,10 +856,10 @@ class SilverStripeInjectionCreator {
|
|||||||
* @param array $params
|
* @param array $params
|
||||||
* An array of parameters to be passed to the constructor
|
* An array of parameters to be passed to the constructor
|
||||||
*/
|
*/
|
||||||
public function create(Injector $injector, $class, $params = array()) {
|
public function create($class, $params = array()) {
|
||||||
$class = Object::getCustomClass($class);
|
$class = Object::getCustomClass($class);
|
||||||
$reflector = new ReflectionClass($class);
|
$reflector = new ReflectionClass($class);
|
||||||
return $reflector->newInstanceArgs($injector->convertServiceProperty($params));
|
return $reflector->newInstanceArgs($params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ class Mailer {
|
|||||||
} else {
|
} else {
|
||||||
$messageParts[] = $this->encodeFileForEmail($file);
|
$messageParts[] = $this->encodeFileForEmail($file);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// We further wrap all of this into another multipart block
|
// We further wrap all of this into another multipart block
|
||||||
@ -233,12 +233,12 @@ class Mailer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @todo Make visibility protected in 3.2
|
* @todo Make visibility protected in 3.2
|
||||||
*/
|
*/
|
||||||
function encodeMultipart($parts, $contentType, $headers = false) {
|
function encodeMultipart($parts, $contentType, $headers = false) {
|
||||||
$separator = "----=_NextPart_" . preg_replace('/[^0-9]/', '', rand() * 10000000000);
|
$separator = "----=_NextPart_" . preg_replace('/[^0-9]/', '', rand() * 10000000000);
|
||||||
|
|
||||||
$headers["MIME-Version"] = "1.0";
|
$headers["MIME-Version"] = "1.0";
|
||||||
@ -261,20 +261,20 @@ class Mailer {
|
|||||||
$separator . implode("\n".$separator, $parts) . "\n" . trim($separator) . "--";
|
$separator . implode("\n".$separator, $parts) . "\n" . trim($separator) . "--";
|
||||||
|
|
||||||
return array($body, $headers);
|
return array($body, $headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @todo Make visibility protected in 3.2
|
* @todo Make visibility protected in 3.2
|
||||||
*/
|
*/
|
||||||
function processHeaders($headers, $body = false) {
|
function processHeaders($headers, $body = false) {
|
||||||
$res = '';
|
$res = '';
|
||||||
if(is_array($headers)) while(list($k, $v) = each($headers))
|
if(is_array($headers)) while(list($k, $v) = each($headers))
|
||||||
$res .= "$k: $v\n";
|
$res .= "$k: $v\n";
|
||||||
if($body) $res .= "\n$body";
|
if($body) $res .= "\n$body";
|
||||||
return $res;
|
return $res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encode the contents of a file for emailing, including headers
|
* Encode the contents of a file for emailing, including headers
|
||||||
*
|
*
|
||||||
* $file can be an array, in which case it expects these members:
|
* $file can be an array, in which case it expects these members:
|
||||||
@ -316,7 +316,7 @@ class Mailer {
|
|||||||
*
|
*
|
||||||
* @todo Make visibility protected in 3.2
|
* @todo Make visibility protected in 3.2
|
||||||
*/
|
*/
|
||||||
function encodeFileForEmail($file, $destFileName = false, $disposition = NULL, $extraHeaders = "") {
|
function encodeFileForEmail($file, $destFileName = false, $disposition = NULL, $extraHeaders = "") {
|
||||||
if(!$file) {
|
if(!$file) {
|
||||||
user_error("encodeFileForEmail: not passed a filename and/or data", E_USER_WARNING);
|
user_error("encodeFileForEmail: not passed a filename and/or data", E_USER_WARNING);
|
||||||
return;
|
return;
|
||||||
@ -352,7 +352,7 @@ class Mailer {
|
|||||||
|
|
||||||
$headers = "Content-type: $mimeType;\n\tname=\"$base\"\n".
|
$headers = "Content-type: $mimeType;\n\tname=\"$base\"\n".
|
||||||
"Content-Transfer-Encoding: $encoding\n".
|
"Content-Transfer-Encoding: $encoding\n".
|
||||||
"Content-Disposition: $disposition;\n\tfilename=\"$base\"\n" ;
|
"Content-Disposition: $disposition;\n\tfilename=\"$base\"\n";
|
||||||
|
|
||||||
if ( isset($file['contentLocation']) ) $headers .= 'Content-Location: ' . $file['contentLocation'] . "\n" ;
|
if ( isset($file['contentLocation']) ) $headers .= 'Content-Location: ' . $file['contentLocation'] . "\n" ;
|
||||||
|
|
||||||
@ -360,12 +360,12 @@ class Mailer {
|
|||||||
|
|
||||||
// Return completed packet
|
// Return completed packet
|
||||||
return $headers . $file['contents'];
|
return $headers . $file['contents'];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @todo Make visibility protected in 3.2
|
* @todo Make visibility protected in 3.2
|
||||||
*/
|
*/
|
||||||
function QuotedPrintable_encode($quotprint) {
|
function QuotedPrintable_encode($quotprint) {
|
||||||
$quotprint = (string)str_replace('\r\n',chr(13).chr(10),$quotprint);
|
$quotprint = (string)str_replace('\r\n',chr(13).chr(10),$quotprint);
|
||||||
$quotprint = (string)str_replace('\n', chr(13).chr(10),$quotprint);
|
$quotprint = (string)str_replace('\n', chr(13).chr(10),$quotprint);
|
||||||
$quotprint = (string)preg_replace("~([\x01-\x1F\x3D\x7F-\xFF])~e", "sprintf('=%02X', ord('\\1'))", $quotprint);
|
$quotprint = (string)preg_replace("~([\x01-\x1F\x3D\x7F-\xFF])~e", "sprintf('=%02X', ord('\\1'))", $quotprint);
|
||||||
@ -375,12 +375,12 @@ class Mailer {
|
|||||||
$quotprint = (string)str_replace('=0D',"\n",$quotprint);
|
$quotprint = (string)str_replace('=0D',"\n",$quotprint);
|
||||||
$quotprint = (string)str_replace('=0A',"\n",$quotprint);
|
$quotprint = (string)str_replace('=0A',"\n",$quotprint);
|
||||||
return (string) $quotprint;
|
return (string) $quotprint;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @todo Make visibility protected in 3.2
|
* @todo Make visibility protected in 3.2
|
||||||
*/
|
*/
|
||||||
function validEmailAddr($emailAddress) {
|
function validEmailAddr($emailAddress) {
|
||||||
$emailAddress = trim($emailAddress);
|
$emailAddress = trim($emailAddress);
|
||||||
$angBrack = strpos($emailAddress, '<');
|
$angBrack = strpos($emailAddress, '<');
|
||||||
|
|
||||||
@ -393,7 +393,7 @@ class Mailer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return $emailAddress;
|
return $emailAddress;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -442,7 +442,7 @@ class InjectorTest extends SapphireTest {
|
|||||||
|
|
||||||
public function testCustomObjectCreator() {
|
public function testCustomObjectCreator() {
|
||||||
$injector = new Injector();
|
$injector = new Injector();
|
||||||
$injector->setObjectCreator(new SSObjectCreator());
|
$injector->setObjectCreator(new SSObjectCreator($injector));
|
||||||
$config = array(
|
$config = array(
|
||||||
'OriginalRequirementsBackend',
|
'OriginalRequirementsBackend',
|
||||||
'DummyRequirements' => array(
|
'DummyRequirements' => array(
|
||||||
@ -485,9 +485,65 @@ class InjectorTest extends SapphireTest {
|
|||||||
$again = $injector->get('NeedsBothCirculars');
|
$again = $injector->get('NeedsBothCirculars');
|
||||||
$this->assertEquals($again->var, 'One');
|
$this->assertEquals($again->var, 'One');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testConvertServicePropertyOnCreate() {
|
||||||
|
// make sure convert service property is not called on direct calls to create, only on configured
|
||||||
|
// declarations to avoid un-needed function calls
|
||||||
|
$injector = new Injector();
|
||||||
|
$item = $injector->create('ConstructableObject', '%$TestObject');
|
||||||
|
$this->assertEquals('%$TestObject', $item->property);
|
||||||
|
|
||||||
|
// do it again but have test object configured as a constructor dependency
|
||||||
|
$injector = new Injector();
|
||||||
|
$config = array(
|
||||||
|
'ConstructableObject' => array(
|
||||||
|
'constructor' => array(
|
||||||
|
'%$TestObject'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$injector->load($config);
|
||||||
|
$item = $injector->get('ConstructableObject');
|
||||||
|
$this->assertTrue($item->property instanceof TestObject);
|
||||||
|
|
||||||
|
// and with a configured object defining TestObject to be something else!
|
||||||
|
$injector = new Injector(array('locator' => 'InjectorTestConfigLocator'));
|
||||||
|
$config = array(
|
||||||
|
'ConstructableObject' => array(
|
||||||
|
'constructor' => array(
|
||||||
|
'%$TestObject'
|
||||||
|
)
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
$injector->load($config);
|
||||||
|
$item = $injector->get('ConstructableObject');
|
||||||
|
$this->assertTrue($item->property instanceof ConstructableObject);
|
||||||
|
|
||||||
|
$this->assertInstanceOf('OtherTestObject', $item->property->property);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestObject {
|
class InjectorTestConfigLocator extends SilverStripeServiceConfigurationLocator implements TestOnly {
|
||||||
|
public function locateConfigFor($name) {
|
||||||
|
if ($name == 'TestObject') {
|
||||||
|
return array('class' => 'ConstructableObject', 'constructor' => array('%$OtherTestObject'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::locateConfigFor($name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConstructableObject implements TestOnly {
|
||||||
|
public $property;
|
||||||
|
|
||||||
|
public function __construct($prop) {
|
||||||
|
$this->property = $prop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestObject implements TestOnly {
|
||||||
|
|
||||||
public $sampleService;
|
public $sampleService;
|
||||||
|
|
||||||
@ -497,7 +553,7 @@ class TestObject {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class OtherTestObject {
|
class OtherTestObject implements TestOnly {
|
||||||
|
|
||||||
private $sampleService;
|
private $sampleService;
|
||||||
|
|
||||||
@ -511,13 +567,13 @@ class OtherTestObject {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class CircularOne {
|
class CircularOne implements TestOnly {
|
||||||
|
|
||||||
public $circularTwo;
|
public $circularTwo;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class CircularTwo {
|
class CircularTwo implements TestOnly {
|
||||||
|
|
||||||
public $circularOne;
|
public $circularOne;
|
||||||
|
|
||||||
@ -528,7 +584,7 @@ class CircularTwo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class NeedsBothCirculars {
|
class NeedsBothCirculars implements TestOnly{
|
||||||
|
|
||||||
public $circularOne;
|
public $circularOne;
|
||||||
public $circularTwo;
|
public $circularTwo;
|
||||||
@ -536,15 +592,15 @@ class NeedsBothCirculars {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyParentClass {
|
class MyParentClass implements TestOnly {
|
||||||
public $one;
|
public $one;
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyChildClass extends MyParentClass {
|
class MyChildClass extends MyParentClass implements TestOnly {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class DummyRequirements {
|
class DummyRequirements implements TestOnly {
|
||||||
|
|
||||||
public $backend;
|
public $backend;
|
||||||
|
|
||||||
@ -558,15 +614,15 @@ class DummyRequirements {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class OriginalRequirementsBackend {
|
class OriginalRequirementsBackend implements TestOnly {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class NewRequirementsBackend {
|
class NewRequirementsBackend implements TestOnly {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class TestStaticInjections {
|
class TestStaticInjections implements TestOnly {
|
||||||
|
|
||||||
public $backend;
|
public $backend;
|
||||||
static $dependencies = array(
|
static $dependencies = array(
|
||||||
@ -582,13 +638,19 @@ class TestStaticInjections {
|
|||||||
* @see https://github.com/silverstripe/sapphire
|
* @see https://github.com/silverstripe/sapphire
|
||||||
*/
|
*/
|
||||||
class SSObjectCreator extends InjectionCreator {
|
class SSObjectCreator extends InjectionCreator {
|
||||||
|
private $injector;
|
||||||
|
|
||||||
public function create(Injector $injector, $class, $params = array()) {
|
public function __construct($injector) {
|
||||||
|
$this->injector = $injector;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function create($class, $params = array()) {
|
||||||
if (strpos($class, '(') === false) {
|
if (strpos($class, '(') === false) {
|
||||||
return parent::create($injector, $class, $params);
|
return parent::create($class, $params);
|
||||||
} else {
|
} else {
|
||||||
list($class, $params) = self::parse_class_spec($class);
|
list($class, $params) = self::parse_class_spec($class);
|
||||||
return parent::create($injector, $class, $params);
|
$params = $this->injector->convertServiceProperty($params);
|
||||||
|
return parent::create($class, $params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user