├── tests ├── .gitignore ├── test-configs │ └── testSimpleStoneValues.properties ├── test-libs │ ├── tests_Person.php │ └── tests_Pair.php ├── README ├── SubstrateUtilPathMatcherTest.php ├── bootstrap.php ├── AllTests.php ├── test-contexts │ └── testSimpleStoneValues.context.php └── SubstrateBasicTest.php ├── .gitignore ├── lib ├── substrate_stones_IOrderedStone.php ├── substrate_IContextStartupAware.php ├── substrate_stones_IPriorityOrderedStone.php ├── substrate_stones_StonesException.php ├── substrate_context_IResourceLoaderAware.php ├── substrate_IClassLoader.php ├── substrate_IPlaceholderConfigurer.php ├── substrate_IResourceLocator.php ├── substrate_stones_factory_IStoneNameAware.php ├── substrate_stones_IContextAware.php ├── substrate_stones_factory_IInitializingStone.php ├── substrate_util_IPathMatcher.php ├── substrate_stones_IContextStartupAware.php ├── substrate_stones_factory_IStoneClassLoaderAware.php ├── substrate_stones_IFactoryStone.php ├── substrate_context_IApplicationContextAware.php ├── substrate_SimplePathResourceLocator.php ├── substrate_stones_factory_IStoneFactoryAware.php ├── substrate_PropertiesDdConfigurationPlaceholderConfigurer.php ├── substrate_ClasspathClassLoader.php ├── substrate_stones_factory_IDisposableStone.php ├── substrate_ContextStoneReference.php ├── substrate_DdConfigurationPlaceholderConfigurer.php ├── substrate_ClasspathResourceLocator.php ├── substrate_dataSource_PdoAdapter.php ├── substrate_ResourceLocatorClassLoader.php ├── substrate_stones_OrderedUtil.php ├── substrate_context_IApplicationContext.php ├── substrate_CompositeClassLoader.php ├── substrate_stones_factory_NoSuchStoneDefinitionException.php ├── substrate_stones_factory_StoneNotOfRequiredTypeException.php ├── substrate_stones_factory_IStoneFactory.php ├── substrate_AbstractClassLoader.php ├── substrate_PathResourceLocator.php ├── substrate_util_AntPathMatcher.php └── substrate_Context.php ├── README ├── vendors ├── dd-core-php │ ├── README │ ├── dd_core_IClassLoader.php │ ├── dd_core_IResourceLocator.php │ ├── dd_core_ClassLoaderUtil.php │ ├── dd_core_ClasspathResourceLocator.php │ ├── dd_core_ResourceLocatorClassLoader.php │ ├── LICENSE │ ├── dd_core_AbstractClassLoader.php │ └── dd_core_PathResourceLocator.php └── dd-configuration-php │ ├── README │ ├── dd_configuration_IResourceLoader.php │ ├── dd_configuration_CompositeConfiguration.php │ ├── dd_configuration_ClasspathResourceLoader.php │ ├── dd_configuration_PdoConfiguration.php │ ├── dd_configuration_MapConfiguration.php │ ├── dd_configuration_IConfiguration.php │ ├── LICENSE.txt │ ├── dd_configuration_Util.php │ ├── dd_configuration_AbstractConfiguration.php │ ├── dd_configuration_PropertiesConfiguration.php │ ├── dd_configuration_Resolver.php │ └── dd_configuration_PathResourceLoader.php └── LICENSE /tests/.gitignore: -------------------------------------------------------------------------------- 1 | bootstrap-site-* 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .buildpath 2 | .project 3 | .settings 4 | ._* 5 | build 6 | dist 7 | repos 8 | -------------------------------------------------------------------------------- /tests/test-configs/testSimpleStoneValues.properties: -------------------------------------------------------------------------------- 1 | person.bill.name=Bill 2 | person.bob.name=Bob 3 | -------------------------------------------------------------------------------- /lib/substrate_stones_IOrderedStone.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/substrate_IContextStartupAware.php: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /lib/substrate_stones_IPriorityOrderedStone.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vendors/dd-core-php/dd_core_IClassLoader.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/substrate_IResourceLocator.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/substrate_stones_factory_IStoneNameAware.php: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /vendors/dd-core-php/dd_core_IResourceLocator.php: -------------------------------------------------------------------------------- 1 | name = $name; 7 | } 8 | public function name() { return $this->name; } 9 | public function setName($name = null) { $this->name = $name; } 10 | } 11 | 12 | ?> -------------------------------------------------------------------------------- /tests/README: -------------------------------------------------------------------------------- 1 | Testing with PHPUnit (http://www.phpunit.de/) 2 | 3 | To run an individual test: 4 | 5 | phpunit SpecificTest.php 6 | 7 | To run all tests it is best to execute the Phing build script 8 | which has the appropriate filters setup to ensure that only 9 | the tests that need to be run will be run. 10 | 11 | phing test 12 | -------------------------------------------------------------------------------- /lib/substrate_stones_factory_IInitializingStone.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/substrate_stones_IContextStartupAware.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/substrate_stones_factory_IStoneClassLoaderAware.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/substrate_context_IApplicationContextAware.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/substrate_stones_factory_IStoneFactoryAware.php: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /vendors/dd-configuration-php/dd_configuration_IResourceLoader.php: -------------------------------------------------------------------------------- 1 | 23 | -------------------------------------------------------------------------------- /lib/substrate_ClasspathClassLoader.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/substrate_stones_factory_IDisposableStone.php: -------------------------------------------------------------------------------- 1 | leader = $leader; 8 | $this->follower = $follower; 9 | } 10 | public function leader() { return $this->leader; } 11 | public function setLeader($leader = null) { $this->leader = $leader; } 12 | public function follower() { return $this->follower; } 13 | public function setFollower($follower = null) { $this->follower = $follower; } 14 | } 15 | 16 | ?> -------------------------------------------------------------------------------- /vendors/dd-core-php/dd_core_ClassLoaderUtil.php: -------------------------------------------------------------------------------- 1 | name = $name; 16 | } 17 | 18 | /** 19 | * Stone's name 20 | * @return string 21 | */ 22 | public function name() { 23 | return $this->name; 24 | } 25 | 26 | /** 27 | * Set the stone's name 28 | * @param $name 29 | */ 30 | public function setName($name) { 31 | $this->name = $name; 32 | } 33 | 34 | } 35 | 36 | ?> -------------------------------------------------------------------------------- /lib/substrate_DdConfigurationPlaceholderConfigurer.php: -------------------------------------------------------------------------------- 1 | configuration = $configuration; 13 | } 14 | 15 | public function replacePlaceholders($value) { 16 | return dd_configuration_Util::RESOLVE_VALUE( 17 | $this->configuration, 18 | $value 19 | ); 20 | } 21 | 22 | } 23 | 24 | ?> -------------------------------------------------------------------------------- /vendors/dd-core-php/dd_core_ClasspathResourceLocator.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /lib/substrate_dataSource_PdoAdapter.php: -------------------------------------------------------------------------------- 1 | dsn = $dsn; 10 | $this->username = $username; 11 | $this->password = $password; 12 | } 13 | public function getObject() { 14 | $pdo = new PDO($this->dsn, $this->username, $this->password); 15 | $pdo->setAttribute( PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION ); 16 | return $pdo; 17 | } 18 | public function getObjectType() { 19 | return PDO.getClass(); 20 | } 21 | } 22 | 23 | ?> 24 | -------------------------------------------------------------------------------- /vendors/dd-configuration-php/dd_configuration_CompositeConfiguration.php: -------------------------------------------------------------------------------- 1 | import($configurations); 26 | } 27 | 28 | } 29 | 30 | ?> 31 | -------------------------------------------------------------------------------- /vendors/dd-core-php/dd_core_ResourceLocatorClassLoader.php: -------------------------------------------------------------------------------- 1 | resourceLocator = $resourceLocator; 15 | } 16 | 17 | /** 18 | * (non-PHPdoc) 19 | * @see dd_core_AbstractClassLoader::find() 20 | */ 21 | public function find($classFileName) { 22 | return $this->resourceLocator->find($classFileName, true); 23 | } 24 | 25 | } -------------------------------------------------------------------------------- /lib/substrate_ResourceLocatorClassLoader.php: -------------------------------------------------------------------------------- 1 | resourceLocator = $resourceLocator; 15 | } 16 | 17 | /** 18 | * (non-PHPdoc) 19 | * @see lib/substrate_AbstractClassLoader::find() 20 | */ 21 | public function find($classFileName) { 22 | return $this->resourceLocator->find($classFileName, true); 23 | } 24 | 25 | } 26 | 27 | ?> -------------------------------------------------------------------------------- /tests/SubstrateUtilPathMatcherTest.php: -------------------------------------------------------------------------------- 1 | assertTrue($pathMatcher->match("**/foo.txt", "hello/world/foo.txt")); 14 | // TODO This next test currently fails, need to explore why. 15 | //$this->assertFalse($pathMatcher->match("*/foo.txt", "hello/world/foo.txt")); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | 38 | -------------------------------------------------------------------------------- /tests/AllTests.php: -------------------------------------------------------------------------------- 1 | addTestSuite($testClassName); 32 | } 33 | return $suite; 34 | } 35 | } 36 | 37 | ?> 38 | -------------------------------------------------------------------------------- /lib/substrate_stones_OrderedUtil.php: -------------------------------------------------------------------------------- 1 | $i2) ? -1 : 0; 20 | } 21 | static public function SORT(array $toBeSorted) { 22 | usort($toBeSorted, array('substrate_stones_OrderedUtil', 'compare')); 23 | return $toBeSorted; 24 | } 25 | static protected function GET_STONE_ORDER($object) { 26 | $order = $object instanceof substrate_stones_IOrderedStone ? $object->getStoneOrder() : null; 27 | return $order !== null ? $order : self::$LOWEST_PRECEDENCE; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /lib/substrate_context_IApplicationContext.php: -------------------------------------------------------------------------------- 1 | prepare($sql); 29 | $sth->execute(); 30 | foreach ( $sth->fetchAll(PDO::FETCH_ASSOC) as $row ) { 31 | $this->map[$row['configurationKey']] = $row['configurationValue']; 32 | } 33 | } 34 | 35 | } 36 | 37 | ?> 38 | -------------------------------------------------------------------------------- /vendors/dd-configuration-php/dd_configuration_MapConfiguration.php: -------------------------------------------------------------------------------- 1 | map); 23 | } 24 | 25 | /** 26 | * Get raw value for key 27 | * 28 | * Value will be returned raw and will not contain any resolved 29 | * results. 30 | * 31 | * @param string $key Key 32 | * @return mixed 33 | */ 34 | public function getRaw($key) { 35 | return array_key_exists($key, $this->map) ? $this->map[$key] : null; 36 | } 37 | 38 | /** 39 | * Set value for a key 40 | * @input string $key Key 41 | * @input mixed $value Value 42 | */ 43 | public function set($key, $value = null) { 44 | $this->map[$key] = $value; 45 | } 46 | 47 | /** 48 | * Does a key exist? 49 | * @input string $key Key 50 | * @return bool 51 | */ 52 | public function exists($key) { 53 | return array_key_exists($key, $this->map); 54 | } 55 | 56 | } 57 | 58 | ?> 59 | -------------------------------------------------------------------------------- /lib/substrate_CompositeClassLoader.php: -------------------------------------------------------------------------------- 1 | classLoaders = $classLoaders; 22 | } 23 | 24 | /** 25 | * Load a class 26 | * @param $className 27 | * @param $includeFilename 28 | */ 29 | public function load($className, $includeFilename = null) { 30 | if ( class_exists($className) ) return true; 31 | if ( isset($this->loadAttemptedLocally[$className]) ) return false; 32 | $this->loadAttemptedLocally[$className] = true; 33 | if ( $includeFilename !== null ) { 34 | // If an include filename was specified, we'll 35 | // just assume that is what we are looking for. 36 | require_once($includeFilename); 37 | return true; 38 | } 39 | foreach ( $this->classLoaders as $classLoader ) { 40 | if ( $classLoader->load($className) ) return true; 41 | } 42 | return false; 43 | } 44 | 45 | } 46 | 47 | ?> -------------------------------------------------------------------------------- /vendors/dd-configuration-php/dd_configuration_IConfiguration.php: -------------------------------------------------------------------------------- 1 | 68 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, Dragonfly Development Inc 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of Dragonfly Development Inc nor the names of its 13 | contributors may be used to endorse or promote products derived from 14 | this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /vendors/dd-core-php/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, Dragonfly Development Inc 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of Dragonfly Development Inc nor the names of its 13 | contributors may be used to endorse or promote products derived from 14 | this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /vendors/dd-configuration-php/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010, Dragonfly Development Inc 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | * Neither the name of Dragonfly Development Inc nor the names of its 13 | contributors may be used to endorse or promote products derived from 14 | this software without specific prior written permission. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 20 | LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 | ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 | POSSIBILITY OF SUCH DAMAGE. 27 | -------------------------------------------------------------------------------- /vendors/dd-configuration-php/dd_configuration_Util.php: -------------------------------------------------------------------------------- 1 | keys() as $key ) { 22 | $importer->set($key, $importee->getRaw($key)); 23 | } 24 | return true; 25 | } 26 | 27 | /** 28 | * Resolve a key 29 | * @param dd_configuration_IConfiguration $configuration Configuration 30 | * @param string $key Key 31 | * @return string Resolved key 32 | */ 33 | static public function RESOLVE_KEY(dd_configuration_IConfiguration $configuration, $key) { 34 | return $configuration->resolver()->resolveKey($configuration, $key); 35 | } 36 | 37 | /** 38 | * Resolve a value 39 | * @param dd_configuration_IConfiguration $configuration Configuration 40 | * @param string $value value 41 | * @return string Resolved key 42 | */ 43 | static public function RESOLVE_VALUE(dd_configuration_IConfiguration $configuration, $value) { 44 | return $configuration->resolver()->resolveValue($configuration, $value); 45 | } 46 | 47 | } 48 | 49 | ?> 50 | -------------------------------------------------------------------------------- /lib/substrate_stones_factory_NoSuchStoneDefinitionException.php: -------------------------------------------------------------------------------- 1 | stoneName = $stoneName; 38 | $this->type = $type; 39 | } 40 | 41 | /** 42 | * Name of the missing stone 43 | * @return string 44 | */ 45 | public function stoneName() { return $this->stoneName; } 46 | 47 | /** 48 | * String representing the type of the missing stone 49 | * @return string 50 | */ 51 | public function type() { return $this->type; } 52 | 53 | } -------------------------------------------------------------------------------- /lib/substrate_stones_factory_StoneNotOfRequiredTypeException.php: -------------------------------------------------------------------------------- 1 | stoneName = $stoneName; 37 | $this->requiredType = $requiredType; 38 | $this->actualType = $actualType; 39 | } 40 | 41 | /** 42 | * Name of stone 43 | * @return string 44 | */ 45 | public function stoneName() { return $this->stoneName; } 46 | 47 | /** 48 | * String representing the required type of the found stone 49 | * @return string 50 | */ 51 | public function requiredType() { return $this->requiredType; } 52 | 53 | /** 54 | * String representing the actual type of the found stone 55 | * @return string 56 | */ 57 | public function actualType() { return $this->actualType; } 58 | 59 | } -------------------------------------------------------------------------------- /vendors/dd-configuration-php/dd_configuration_AbstractConfiguration.php: -------------------------------------------------------------------------------- 1 | resolver === null ) { 43 | $this->resolver = new dd_configuration_Resolver($this); 44 | } 45 | return $this->resolver; 46 | } 47 | 48 | /** 49 | * Import another configuration 50 | * @param mixed $input dd_configuration_IConfiguration or array 51 | */ 52 | public function import($configuration) { 53 | if ( ! is_array($configuration) ) { 54 | $configuration = array($configuration); 55 | } 56 | foreach ( $configuration as $item ) { 57 | if ( ! dd_configuration_Util::IMPORT($this, $item) ) { 58 | return false; 59 | } 60 | } 61 | return true; 62 | } 63 | 64 | } 65 | 66 | ?> 67 | -------------------------------------------------------------------------------- /lib/substrate_stones_factory_IStoneFactory.php: -------------------------------------------------------------------------------- 1 | add('jon', array( 3 | 'className' => 'tests_Person', 4 | 'constructorArgs' => array( 5 | 'name' => 'Jon', 6 | ), 7 | )); 8 | 9 | $context->add('jane', array( 10 | 'className' => 'tests_Person', 11 | 'properties' => array( 12 | 'name' => 'Jane', 13 | ), 14 | )); 15 | 16 | $context->add('jonAndJaneConstructor', array( 17 | 'className' => 'tests_Pair', 18 | 'constructorArgs' => array( 19 | 'leader' => $context->ref('jon'), 20 | 'follower' => $context->ref('jane'), 21 | ), 22 | )); 23 | 24 | $context->add('jonAndJaneProperties', array( 25 | 'className' => 'tests_Pair', 26 | 'properties' => array( 27 | 'leader' => $context->ref('jon'), 28 | 'follower' => $context->ref('jane'), 29 | ), 30 | )); 31 | 32 | $context->add('jonAndJaneMixed', array( 33 | 'className' => 'tests_Pair', 34 | 'constructorArgs' => array( 35 | 'leader' => $context->ref('jon'), 36 | ), 37 | 'properties' => array( 38 | 'follower' => $context->ref('jane'), 39 | ), 40 | )); 41 | 42 | $context->add('bobAndBill', array( 43 | 'className' => 'tests_Pair', 44 | 'constructorArgs' => array( 45 | 'follower' => $context->add(array( 46 | 'className' => 'tests_Person', 47 | 'properties' => array('name' => '${person.bill.name}'), 48 | )), 49 | ), 50 | 'properties' => array( 51 | 'leader' => $context->add(array( 52 | 'className' => 'tests_Person', 53 | 'properties' => array('name' => '${person.bob.name}'), 54 | )), 55 | ), 56 | )); 57 | 58 | // Application Configuration. 59 | $context->add('configuration', array( 60 | 'className' => 'dd_configuration_PropertiesConfiguration', 61 | 'constructorArgs' => array( 62 | 'locations' => array( 63 | 'testSimpleStoneValues.properties', 64 | ), 65 | ), 66 | )); 67 | 68 | // Placeholder Configurer is used to replace ${property.key.names} with 69 | // the values found inside of a configuration object. 70 | $context->add('placeholderConfigurer', array( 71 | 'className' => 'substrate_DdConfigurationPlaceholderConfigurer', 72 | 'constructorArgs' => array( 73 | 'configuration' => $context->ref('configuration'), 74 | ), 75 | )); 76 | 77 | ?> 78 | -------------------------------------------------------------------------------- /tests/SubstrateBasicTest.php: -------------------------------------------------------------------------------- 1 | execute(); 32 | 33 | $personJon = $context->get('jon'); 34 | $personJane = $context->get('jane'); 35 | 36 | $this->assertEquals('Jon', $personJon->name()); 37 | $this->assertEquals('Jane', $personJane->name()); 38 | 39 | $jonAndJaneConstructor = $context->get('jonAndJaneConstructor'); 40 | 41 | $this->assertTrue($jonAndJaneConstructor->leader() == $personJon); 42 | $this->assertTrue($jonAndJaneConstructor->follower() == $personJane); 43 | 44 | $jonAndJaneProperties = $context->get('jonAndJaneProperties'); 45 | 46 | $this->assertTrue($jonAndJaneProperties->leader() == $personJon); 47 | $this->assertTrue($jonAndJaneProperties->follower() == $personJane); 48 | 49 | $jonAndJaneMixed = $context->get('jonAndJaneMixed'); 50 | 51 | $this->assertTrue($jonAndJaneMixed->leader() == $personJon); 52 | $this->assertTrue($jonAndJaneMixed->follower() == $personJane); 53 | 54 | $people = $context->findStonesByImplementation('tests_Person'); 55 | $this->assertEquals(2, count($people)); 56 | 57 | $bobAndBill = $context->get('bobAndBill'); 58 | $this->assertEquals('Bob', $bobAndBill->leader()->name()); 59 | $this->assertEquals('Bill', $bobAndBill->follower()->name()); 60 | 61 | $people = $context->findStonesByImplementation('tests_Person'); 62 | $this->assertEquals(4, count($people)); 63 | 64 | } 65 | 66 | } 67 | ?> 68 | -------------------------------------------------------------------------------- /lib/substrate_AbstractClassLoader.php: -------------------------------------------------------------------------------- 1 | templateCallbacks = $templateCallbacks; 29 | } else { 30 | $this->templateCallbacks = array( 31 | array('substrate_AbstractClassLoader', 'SIMPLE_CLASS_TEMPLATE'), 32 | ); 33 | } 34 | } 35 | 36 | /** 37 | * Load a class 38 | * @param $className 39 | * @param $includeFilename 40 | */ 41 | public function load($className, $includeFilename = null) { 42 | if ( class_exists($className) ) return true; 43 | if ( isset($this->loadAttemptedLocally[$className]) ) return false; 44 | $this->loadAttemptedLocally[$className] = true; 45 | if ( $includeFilename !== null ) { 46 | // If an include filename was specified, we'll 47 | // just assume that is what we are looking for. 48 | require_once($includeFilename); 49 | return true; 50 | } 51 | foreach ( $this->potentialIncludeFilenames($className) as $includeFilename ) { 52 | if ( $fullIncludePath = $this->find($includeFilename) ) { 53 | require_once($fullIncludePath); 54 | return true; 55 | } 56 | } 57 | return false; 58 | } 59 | 60 | /** 61 | * Determine potential include filenames for the specified class name 62 | * @param $className 63 | */ 64 | public function potentialIncludeFilenames($className) { 65 | $potentialIncludeFilenames = array(); 66 | foreach ( $this->templateCallbacks as $callback ) { 67 | $potentialIncludeFilenames[] = call_user_func($callback, $className); 68 | } 69 | return $potentialIncludeFilenames; 70 | } 71 | 72 | /** 73 | * Leave the finding of the class filename up to subclasses 74 | * @param $classFileName 75 | */ 76 | abstract public function find($classFileName); 77 | 78 | } 79 | 80 | ?> -------------------------------------------------------------------------------- /vendors/dd-core-php/dd_core_AbstractClassLoader.php: -------------------------------------------------------------------------------- 1 | templateCallbacks = $templateCallbacks; 29 | } else { 30 | $this->templateCallbacks = array( 31 | // TODO Figure out a better way to handle this 32 | array('dd_core_AbstractClassLoader', 'SIMPLE_CLASS_TEMPLATE'), 33 | ); 34 | } 35 | } 36 | 37 | /** 38 | * Load a class 39 | * @param $className 40 | * @param $includeFilename 41 | */ 42 | public function load($className, $includeFilename = null) { 43 | if ( class_exists($className) ) return true; 44 | if ( isset($this->loadAttemptedLocally[$className]) ) return false; 45 | $this->loadAttemptedLocally[$className] = true; 46 | if ( $includeFilename !== null ) { 47 | // If an include filename was specified, we'll 48 | // just assume that is what we are looking for. 49 | require_once($includeFilename); 50 | return true; 51 | } 52 | foreach ( $this->potentialIncludeFilenames($className) as $includeFilename ) { 53 | if ( $fullIncludePath = $this->find($includeFilename) ) { 54 | require_once($fullIncludePath); 55 | return true; 56 | } 57 | } 58 | return false; 59 | } 60 | 61 | /** 62 | * Determine potential include filenames for the specified class name 63 | * @param $className 64 | */ 65 | public function potentialIncludeFilenames($className) { 66 | $potentialIncludeFilenames = array(); 67 | foreach ( $this->templateCallbacks as $callback ) { 68 | $potentialIncludeFilenames[] = call_user_func($callback, $className); 69 | } 70 | return $potentialIncludeFilenames; 71 | } 72 | 73 | /** 74 | * Leave the finding of the class filename up to subclasses 75 | * @param $classFileName 76 | */ 77 | abstract public function find($classFileName); 78 | 79 | } 80 | -------------------------------------------------------------------------------- /vendors/dd-configuration-php/dd_configuration_PropertiesConfiguration.php: -------------------------------------------------------------------------------- 1 | resourceLoader = new dd_configuration_ClasspathResourceLoader( 37 | isset($trace[0]['file']) ? $trace[0]['file'] : null 38 | ); 39 | } 40 | else $this->resourceLoader = $resourceLoader; 41 | 42 | if ( $locations !== null ) $this->addLocations($locations); 43 | 44 | } 45 | 46 | /** 47 | * Add properties file locations 48 | * 49 | * May accept a string specifying location or an array containing 50 | * multiple location strings. This is the most flexible way to 51 | * add locations. 52 | * 53 | * @param mixed $locations Locations 54 | */ 55 | public function addLocations($locations = null) { 56 | 57 | if ( $locations !== null ) { 58 | if ( ! is_array($locations) ) $locations = array($locations); 59 | foreach ( $locations as $location ) { 60 | $this->addLocation($location); 61 | } 62 | } 63 | 64 | } 65 | 66 | /** 67 | * Add a properties file location 68 | * 69 | * Requires passed value to be a location string. 70 | * 71 | * @param string $location Location 72 | */ 73 | public function addLocation($location) { 74 | 75 | if ( is_array($location) ) throw new Exception('Cannot specify location as an array'); 76 | 77 | $path = $this->resourceLoader->find($location); 78 | 79 | if ( $path !== null ) { 80 | 81 | $this->locations[] = $path; 82 | 83 | $content = file_get_contents($path); 84 | 85 | foreach ( explode("\n", $content) as $line ) { 86 | 87 | preg_match('/^\s*([^=]+?)\s*=\s*(.+?)\s*$/', $line, $matches); 88 | 89 | if ( count($matches) > 1 && strlen($matches[1]) > 0 && strpos($matches[1], '#') !== 0) { 90 | $this->map[$matches[1]] = $matches[2]; 91 | } 92 | 93 | } 94 | 95 | } 96 | 97 | } 98 | 99 | } 100 | 101 | ?> 102 | -------------------------------------------------------------------------------- /vendors/dd-configuration-php/dd_configuration_Resolver.php: -------------------------------------------------------------------------------- 1 | resolved) ) { 29 | $this->resolved[$key] = $this->resolveValue($configuration, $configuration->getRaw($key)); 30 | } 31 | return $this->resolved[$key]; 32 | } 33 | 34 | /** 35 | * Resolve a value 36 | * @param dd_configuration_IConfiguration $configuration Configuration 37 | * @param string $key Key 38 | * @return string 39 | */ 40 | public function resolveValue(dd_configuration_IConfiguration $configuration, $value) { 41 | 42 | $counter = 0; 43 | $resolverCallback = new dd_configuration_ResolverCallback( 44 | $configuration 45 | ); 46 | while ( true ) { 47 | 48 | $newValue = preg_replace_callback( 49 | '/\${([a-zA-Z0-9\.\(\)_\:]+?)}/', 50 | array($resolverCallback, 'resolveCallback'), 51 | $value 52 | ); 53 | 54 | if ( $newValue === $value ) { 55 | break; 56 | } 57 | 58 | $value = $newValue; 59 | 60 | // Break recursion if depth goes beyond 10! 61 | // TODO Make this configurable? 62 | if ( $counter++ > 10 ) break; 63 | 64 | } 65 | 66 | return $value; 67 | 68 | } 69 | 70 | } 71 | 72 | /** 73 | * Configuration Resolver Callback. 74 | * @package dd_configuration 75 | */ 76 | class dd_configuration_ResolverCallback { 77 | 78 | /** 79 | * Configuration 80 | * @var dd_configuration_IConfiguration 81 | */ 82 | protected $configuration; 83 | 84 | /** 85 | * Constructor 86 | * @param dd_configuration_IConfiguration $configuration Configuration 87 | */ 88 | public function __construct(dd_configuration_IConfiguration $configuration) { 89 | $this->configuration = $configuration; 90 | } 91 | 92 | /** 93 | * preg_replace_callback Callback. 94 | * @param array $matches Matches 95 | */ 96 | public function resolveCallback($matches) { 97 | $key = $matches[1]; 98 | if ( preg_match('/^(ENV|SERVER|CONSTANT):(\w+)$/', $key, $special) ) { 99 | list($whole, $which, $key) = $special; 100 | if ( $which == 'ENV' ) { 101 | if ( array_key_exists($key, $_ENV) ) { 102 | return $_ENV[$key]; 103 | } 104 | } elseif ( $which == 'SERVER' ) { 105 | if ( array_key_exists($key, $_SERVER) ) { 106 | return $_SERVER[$key]; 107 | } 108 | } elseif ( $which == 'CONSTANT' ) { 109 | if ( defined($key) ) { 110 | return constant($key); 111 | } 112 | } 113 | } 114 | if ( $this->configuration->exists($key) ) { 115 | return $this->configuration->get($key); 116 | } 117 | return $matches[0]; 118 | } 119 | 120 | } 121 | 122 | ?> 123 | -------------------------------------------------------------------------------- /vendors/dd-core-php/dd_core_PathResourceLocator.php: -------------------------------------------------------------------------------- 1 | callingFile = $callingFile; 42 | } 43 | if ( $paths !== null ) { 44 | if ( ! is_array($paths) ) { 45 | $paths = array($paths); 46 | } 47 | foreach ( $paths as $path ) { 48 | $this->paths[] = $path; 49 | } 50 | } 51 | if ( $prependedPaths !== null ) { 52 | if ( ! is_array($prependedPaths) ) { 53 | $prependedPaths = array($prependedPaths); 54 | } 55 | foreach ( $prependedPaths as $path ) { 56 | $this->prependedPaths[] = $path; 57 | } 58 | } 59 | if ( $appendedPaths !== null ) { 60 | if ( ! is_array($appendedPaths) ) { 61 | $appendedPaths = array($appendedPaths); 62 | } 63 | foreach ( $appendedPaths as $path ) { 64 | $this->appendedPaths[] = $path; 65 | } 66 | } 67 | } 68 | 69 | /** 70 | * Find a target file 71 | * @param string $target Target 72 | * @return string 73 | */ 74 | public function find($target, $realPath = false) { 75 | 76 | if ( strpos($target, '/') === 0 ) { 77 | if ( file_exists($target) ) return $realPath ? realpath($target) : $target; 78 | return null; 79 | } 80 | 81 | foreach ( $this->allPaths() as $path ) { 82 | $testLocation = $path . '/' . $target; 83 | // TODO This could possibly be cached eventually. 84 | if ( file_exists($testLocation) ) return $realPath ? realpath($testLocation) : $testLocation; 85 | } 86 | 87 | // Could not be found. 88 | return null; 89 | 90 | } 91 | 92 | /** 93 | * Paths to search 94 | * @return array 95 | */ 96 | public function allPaths() { 97 | $callingFiles = array(); 98 | if ( $this->callingFile ) $callingFiles[] = dirname($this->callingFile); 99 | return array_merge( 100 | $callingFiles, 101 | $this->prependedPaths(), 102 | $this->paths(), 103 | $this->appendedPaths() 104 | ); 105 | 106 | } 107 | 108 | /** 109 | * Paths 110 | * @return array 111 | */ 112 | public function paths() { 113 | return $this->paths; 114 | } 115 | 116 | /** 117 | * Prepend a path to the classpath 118 | * @param string $path Path 119 | */ 120 | public function prependPath($path) { 121 | array_unshift($this->prependedPaths, $path); 122 | } 123 | 124 | /** 125 | * Append a path to the classpath 126 | * @param string $path Path 127 | */ 128 | public function appendPath($path) { 129 | push($this->appendedPaths, $path); 130 | } 131 | 132 | /** 133 | * Prepended paths 134 | * @return array 135 | */ 136 | public function prependedPaths() { 137 | return $this->prependedPaths; 138 | } 139 | 140 | /** 141 | * Appended paths 142 | * @return array 143 | */ 144 | public function appendedPaths() { 145 | return $this->appendedPaths; 146 | } 147 | 148 | } -------------------------------------------------------------------------------- /lib/substrate_PathResourceLocator.php: -------------------------------------------------------------------------------- 1 | callingFile = $callingFile; 42 | } 43 | if ( $paths !== null ) { 44 | if ( ! is_array($paths) ) { 45 | $paths = array($paths); 46 | } 47 | foreach ( $paths as $path ) { 48 | $this->paths[] = $path; 49 | } 50 | } 51 | if ( $prependedPaths !== null ) { 52 | if ( ! is_array($prependedPaths) ) { 53 | $prependedPaths = array($prependedPaths); 54 | } 55 | foreach ( $prependedPaths as $path ) { 56 | $this->prependedPaths[] = $path; 57 | } 58 | } 59 | if ( $appendedPaths !== null ) { 60 | if ( ! is_array($appendedPaths) ) { 61 | $appendedPaths = array($appendedPaths); 62 | } 63 | foreach ( $appendedPaths as $path ) { 64 | $this->appendedPaths[] = $path; 65 | } 66 | } 67 | } 68 | 69 | /** 70 | * Find a target file 71 | * @param string $target Target 72 | * @return string 73 | */ 74 | public function find($target, $realPath = false) { 75 | 76 | if ( strpos($target, '/') === 0 ) { 77 | if ( file_exists($target) ) return $realPath ? realpath($target) : $target; 78 | return null; 79 | } 80 | 81 | foreach ( $this->allPaths() as $path ) { 82 | $testLocation = $path . '/' . $target; 83 | // TODO This could possibly be cached eventually. 84 | if ( file_exists($testLocation) ) return $realPath ? realpath($testLocation) : $testLocation; 85 | } 86 | 87 | // Could not be found. 88 | return null; 89 | 90 | } 91 | 92 | /** 93 | * Paths to search 94 | * @return array 95 | */ 96 | public function allPaths() { 97 | $callingFiles = array(); 98 | if ( $this->callingFile ) $callingFiles[] = dirname($this->callingFile); 99 | return array_merge( 100 | $callingFiles, 101 | $this->prependedPaths(), 102 | $this->paths(), 103 | $this->appendedPaths() 104 | ); 105 | 106 | } 107 | 108 | /** 109 | * Paths 110 | * @return array 111 | */ 112 | public function paths() { 113 | return $this->paths; 114 | } 115 | 116 | /** 117 | * Prepend a path to the classpath 118 | * @param string $path Path 119 | */ 120 | public function prependPath($path) { 121 | array_unshift($this->prependedPaths, $path); 122 | } 123 | 124 | /** 125 | * Append a path to the classpath 126 | * @param string $path Path 127 | */ 128 | public function appendPath($path) { 129 | push($this->appendedPaths, $path); 130 | } 131 | 132 | /** 133 | * Prepended paths 134 | * @return array 135 | */ 136 | public function prependedPaths() { 137 | return $this->prependedPaths; 138 | } 139 | 140 | /** 141 | * Appended paths 142 | * @return array 143 | */ 144 | public function appendedPaths() { 145 | return $this->appendedPaths; 146 | } 147 | 148 | } 149 | 150 | ?> -------------------------------------------------------------------------------- /vendors/dd-configuration-php/dd_configuration_PathResourceLoader.php: -------------------------------------------------------------------------------- 1 | callingFile = $callingFile; 51 | } 52 | if ( $paths !== null ) { 53 | if ( ! is_array($paths) ) { 54 | $paths = array($paths); 55 | } 56 | foreach ( $paths as $path ) { 57 | $this->paths[] = $path; 58 | } 59 | } 60 | if ( $prependedPaths !== null ) { 61 | if ( ! is_array($prependedPaths) ) { 62 | $prependedPaths = array($prependedPaths); 63 | } 64 | foreach ( $prependedPaths as $path ) { 65 | $this->prependedPaths[] = $path; 66 | } 67 | } 68 | if ( $appendedPaths !== null ) { 69 | if ( ! is_array($appendedPaths) ) { 70 | $appendedPaths = array($appendedPaths); 71 | } 72 | foreach ( $appendedPaths as $path ) { 73 | $this->appendedPaths[] = $path; 74 | } 75 | } 76 | } 77 | 78 | /** 79 | * Find the path for a location 80 | * @param string $location Location 81 | * @return string 82 | */ 83 | public function find($location) { 84 | 85 | foreach ( $this->allPaths() as $path ) { 86 | $testLocation = $path . '/' . $location; 87 | // TODO This could possibly be cached eventually. 88 | if ( file_exists($testLocation) ) return $testLocation; 89 | } 90 | 91 | // Could not be found. 92 | return null; 93 | 94 | } 95 | 96 | /** 97 | * Paths to search 98 | * @return array 99 | */ 100 | public function allPaths() { 101 | 102 | $callingFiles = array(); 103 | if ( $this->callingFile ) $callingFiles[] = dirname($this->callingFile); 104 | 105 | return array_merge( 106 | $callingFiles, 107 | $this->prependedPaths(), 108 | $this->paths(), 109 | $this->appendedPaths() 110 | ); 111 | 112 | } 113 | 114 | /** 115 | * Paths 116 | * @return array 117 | */ 118 | public function paths() { 119 | return $this->paths; 120 | } 121 | 122 | /** 123 | * Prepend a path to the classpath 124 | * @param string $path Path 125 | */ 126 | public function prependPath($path) { 127 | array_unshift($this->prependedPaths, $path); 128 | } 129 | 130 | /** 131 | * Append a path to the classpath 132 | * @param string $path Path 133 | */ 134 | public function appendPath($path) { 135 | push($this->appendedPaths, $path); 136 | } 137 | 138 | /** 139 | * Prepended paths 140 | * @return array 141 | */ 142 | public function prependedPaths() { 143 | return $this->prependedPaths; 144 | } 145 | 146 | /** 147 | * Appended paths 148 | * @return array 149 | */ 150 | public function appendedPaths() { 151 | return $this->appendedPaths; 152 | } 153 | 154 | 155 | } 156 | 157 | ?> 158 | -------------------------------------------------------------------------------- /lib/substrate_util_AntPathMatcher.php: -------------------------------------------------------------------------------- 1 | $pathIdxEnd) { 67 | // All characters in the string are used. Check if only '*'s are 68 | // left in the pattern. If so, we succeeded. Otherwise failure. 69 | for ($i = $patIdxStart; $i <= $patIdxEnd; $i++) { 70 | if ($patArr[$i] != '*') { 71 | return false; 72 | } 73 | } 74 | return true; 75 | } 76 | 77 | // Process characters after last star 78 | while (($ch = $patArr[$patIdxEnd]) != '*' && $pathIdxStart <= $pathIdxEnd) { 79 | if ($ch != '?') { 80 | if ($isCaseSensitive && $ch != $pathArr[$pathIdxEnd]) { 81 | return false; // Character mismatch 82 | } 83 | if (!$isCaseSensitive && strtoupper($ch) 84 | != strtoupper($pathArr[$pathIdxEnd])) { 85 | return false; // Character mismatch 86 | } 87 | } 88 | $patIdxEnd--; 89 | $pathIdxEnd--; 90 | } 91 | if ($pathIdxStart > $pathIdxEnd) { 92 | // All characters in the string are used. Check if only '*'s are 93 | // left in the pattern. If so, we succeeded. Otherwise failure. 94 | for ($i = $patIdxStart; $i <= $patIdxEnd; $i++) { 95 | if ($patArr[$i] != '*') { 96 | return false; 97 | } 98 | } 99 | return true; 100 | } 101 | 102 | // process pattern between stars. padIdxStart and patIdxEnd point 103 | // always to a '*'. 104 | while ($patIdxStart != $patIdxEnd && $pathIdxStart <= $pathIdxEnd) { 105 | $patIdxTmp = -1; 106 | for ($i = $patIdxStart + 1; $i <= $patIdxEnd; $i++) { 107 | if ($patArr[$i] == '*') { 108 | $patIdxTmp = $i; 109 | break; 110 | } 111 | } 112 | if ($patIdxTmp == $patIdxStart + 1) { 113 | // Two stars next to each other, skip the first one. 114 | $patIdxStart++; 115 | continue; 116 | } 117 | // Find the pattern between padIdxStart & padIdxTmp in str between 118 | // strIdxStart & strIdxEnd 119 | $patLength = ($patIdxTmp - $patIdxStart - 1); 120 | $pathLength = ($pathIdxEnd - $pathIdxStart + 1); 121 | $foundIdx = -1; 122 | //strLoop: 123 | for ($i = 0; $i <= $pathLength - $patLength; $i++) { 124 | for ($j = 0; $j < $patLength; $j++) { 125 | $ch = $patArr[$patIdxStart + $j + 1]; 126 | if ($ch != '?') { 127 | if ($isCaseSensitive && $ch != $pathArr[$pathIdxStart + $i 128 | + $j]) { 129 | continue 2; 130 | //continue strLoop; 131 | } 132 | if (!$isCaseSensitive 133 | && strtoupper($ch) 134 | != strtoupper($pathArr[$pathIdxStart + $i + $j])) { 135 | continue 2; 136 | //continue strLoop; 137 | } 138 | } 139 | } 140 | $foundIdx = $pathIdxStart + $i; 141 | break; 142 | } 143 | 144 | if ($foundIdx == -1) { 145 | return false; 146 | } 147 | 148 | $patIdxStart = $patIdxTmp; 149 | $pathIdxStart = $foundIdx + $patLength; 150 | } 151 | 152 | // All characters in the string are used. Check if only '*'s are left 153 | // in the pattern. If so, we succeeded. Otherwise failure. 154 | for ($i = $patIdxStart; $i <= $patIdxEnd; $i++) { 155 | if ($patArr[$i] != '*') { 156 | return false; 157 | } 158 | } 159 | 160 | return true; 161 | 162 | } 163 | 164 | } 165 | 166 | ?> -------------------------------------------------------------------------------- /lib/substrate_Context.php: -------------------------------------------------------------------------------- 1 | benchmarkStart = microtime(true); 150 | $this->id = self::$ID_COUNTER++; 151 | if ( $contextResourceLocator === null ) { 152 | $this->contextResourceLocator = self::CLASSPATH_RESOURCE_LOCATOR(); 153 | } else { 154 | $this->contextResourceLocator = $contextResourceLocator; 155 | } 156 | if ( $classLoader === null ) { 157 | $this->classLoader = self::CLASSPATH_CLASS_LOADER(); 158 | } else { 159 | $this->classLoader = $classLoader; 160 | } 161 | $this->import($contextConfigNames); 162 | } 163 | 164 | /** 165 | * Destructor 166 | */ 167 | public function __destruct() { 168 | $this->logDebug('Context lived for ' . ( microtime(true) - $this->benchmarkStart ) . ' seconds'); 169 | } 170 | 171 | /** 172 | * Import context configurations 173 | * @param mixed $contextConfigNames 174 | * @param bool $autoExecute 175 | */ 176 | public function import($contextConfigNames, $autoExecute = false) { 177 | 178 | if ( $this->importingDepth == 0 ) { 179 | $originalStoneNames = $this->registeredStoneNames(); 180 | } 181 | 182 | if ( ! is_array($contextConfigNames) ) { 183 | $contextConfigNames = array($contextConfigNames); 184 | } 185 | 186 | $context = $this; 187 | 188 | $this->importingDepth++; 189 | foreach ( $contextConfigNames as $contextConfigName ) { 190 | $contextFilePath = $this->contextResourceLocator->find($contextConfigName); 191 | if ( file_exists($contextFilePath) ) { 192 | $this->logInfo('Importing object definitions for "' . $contextConfigName . '" from "' . $contextFilePath . '"'); 193 | include($contextFilePath); 194 | } else { 195 | $this->logError('Could not find context configuration for "' . $contextConfigName . '"'); 196 | } 197 | } 198 | $this->importingDepth--; 199 | 200 | if ( $this->importingDepth == 0 ) { 201 | $currentStoneNames = $this->registeredStoneNames(); 202 | $this->recentlyDefinedStones = array_diff($currentStoneNames, $originalStoneNames); 203 | if ( count($this->recentlyDefinedStones) ) { 204 | $this->logInfo('Added stone definitions for: ' . implode(', ', $this->recentlyDefinedStones)); 205 | } else { 206 | $this->logInfo('No stones found in context configuration(s): ' . implode(', ', $contextConfigNames));; 207 | } 208 | } 209 | 210 | if ( $autoExecute ) { 211 | $this->execute(); 212 | } 213 | 214 | } 215 | 216 | /** 217 | * Execute the Substrate context 218 | */ 219 | public function execute() { 220 | $this->initializeLogging(); 221 | $this->placeholderConfigurer(); 222 | foreach ( $this->stoneDefinitions as $name => $setup ) { 223 | if ( ! isset($this->preparedStones[$name]) ) { 224 | // TODO: This is not DRY. See get() 225 | $stoneDefinition = $this->prepareStone($name); 226 | $this->stoneDefinitions[$name] = $stoneDefinition; 227 | $this->preparedStones[$name] = true; 228 | } 229 | if ( ! $this->stoneDefinitions[$name]['lazyLoad'] ) { 230 | $this->instantiate($name); 231 | } 232 | } 233 | } 234 | 235 | /** 236 | * Check if stone has been defined 237 | * @param $name 238 | */ 239 | public function exists($name = null) { 240 | return array_key_exists($name, $this->stoneDefinitions); 241 | } 242 | 243 | /** 244 | * Is a stone instantiated? 245 | * @param $name 246 | */ 247 | protected function instantiated($name = null) { 248 | return array_key_exists($name, $this->stoneInstances); 249 | } 250 | 251 | /** 252 | * Is a stone initialized? 253 | * Enter description here ... 254 | * @param unknown_type $name 255 | */ 256 | protected function initialized($name = null) { 257 | return array_key_exists($name, $this->initializedStones); 258 | } 259 | 260 | /** 261 | * Instantiate a stone 262 | * @param $name 263 | * @throws Exception 264 | */ 265 | protected function instantiate($name = null) { 266 | 267 | if ( $name === null ) throw new Exception('Object name must be specified.'); 268 | if ( $this->instantiated($name)) { return $this->stoneInstances[$name]; } 269 | 270 | $setup = $this->stoneDefinition($name); 271 | $className = $setup['className']; 272 | $this->logDebug('Initializing stone named "' . $name . '" (' . $className . ')'); 273 | $this->loadDependantClasses($setup); 274 | 275 | $reflectionClass = new ReflectionClass($className); 276 | 277 | $constructor = $reflectionClass->getConstructor(); 278 | $constructorArgs = array(); 279 | 280 | $originalConstructorArgs = isset($setup['constructorArgs']) ? 281 | $setup['constructorArgs'] : null; 282 | 283 | if ( $constructor ) { 284 | 285 | foreach ( $constructor->getParameters() as $reflectionParamter ) { 286 | 287 | $constructorArgumentName = $reflectionParamter->getName(); 288 | if ( isset($setup['constructorArgs'][$constructorArgumentName]) ) { 289 | $constructorArgs[] = $setup['constructorArgs'][$constructorArgumentName]; 290 | // We no longer want to remember this constructor argument. 291 | unset($originalConstructorArgs[$constructorArgumentName]); 292 | } else { 293 | $throwException = true; 294 | $foundArgument = false; 295 | $paramClass = $reflectionParamter->getClass(); 296 | if ( $paramClass ) { 297 | $paramClassName = $paramClass->getName(); 298 | foreach ( $this->stoneInstances as $testStone ) { 299 | if ( $testStone instanceof $paramClassName ) { 300 | $throwException = false; 301 | $foundArgument = true; 302 | if ( ! $reflectionParamter->allowsNull() ) { 303 | // TODO: We should have some sort of auto wiring 304 | // kill switch. This "only if not null" might be 305 | // a bit hard to track down. 306 | $constructorArgs[] = $testStone; 307 | } 308 | break; 309 | } 310 | } 311 | } 312 | if ( ! $foundArgument and $reflectionParamter->allowsNull() ) { 313 | $throwException = false; 314 | } 315 | if ( $throwException ) { 316 | throw new Exception('Could not find constructor argument named "' . $constructorArgumentName . '" for stone named "' . $name . '"'); 317 | } 318 | if ( ! $foundArgument ) $constructorArgs[] = null; 319 | } 320 | } 321 | 322 | if ( count($originalConstructorArgs) ) { 323 | $constructorArgs = array_merge($constructorArgs, array_values($originalConstructorArgs)); 324 | } 325 | 326 | } 327 | 328 | if ( sizeof($constructorArgs) ) { 329 | for ( $i = 0; $i < count($constructorArgs); $i++ ) { 330 | $constructorArgs[$i] = 331 | $this->resolvedConstructorArg($constructorArgs[$i]); 332 | } 333 | $newInstance = $reflectionClass->newInstanceArgs($constructorArgs); 334 | } else { 335 | $newInstance = $reflectionClass->newInstance(); 336 | } 337 | 338 | $references = array(); 339 | foreach ( $setup['properties'] as $key => $value ) { 340 | $methodName = 'set' . ucfirst($key); 341 | if ( method_exists($newInstance, $methodName) ) { 342 | if ( $value instanceof substrate_ContextStoneReference ) { 343 | $references[] = array( 344 | 'methodName' => $methodName, 345 | 'contextStoneReference' => $value, 346 | ); 347 | } else { 348 | $newInstance->$methodName($value); 349 | } 350 | } 351 | } 352 | 353 | foreach ( $setup['dependencies'] as $value ) { 354 | $references[] = array( 355 | 'methodName' => null, 356 | 'contextStoneReference' => $value, 357 | ); 358 | } 359 | 360 | if ( $newInstance instanceof substrate_stones_IFactoryStone ) { 361 | // TODO Make new instance factory stone aware? 362 | $newInstance = $newInstance->getObject(); 363 | } 364 | 365 | $this->stoneInstances[$name] = $newInstance; 366 | 367 | if ( count($references) ) { 368 | // If there are references, we can try to load them now. 369 | // We do this AFTER we have stored our stone reference 370 | // so that we can avoid infinite loops for stones that 371 | // have a dependency on each other. 372 | $this->loadReferences($name, $references); 373 | } 374 | 375 | if ( $newInstance !== null ) { 376 | 377 | $this->addInterfacetoMap(get_class($newInstance), $name); 378 | 379 | foreach ( class_implements($newInstance) as $implementedInterface ) { 380 | $this->addInterfaceToMap($implementedInterface, $name); 381 | } 382 | 383 | foreach ( class_parents($newInstance) as $parentClass ) { 384 | $this->addInterfaceToMap($parentClass, $name); 385 | } 386 | 387 | } 388 | 389 | return $newInstance; 390 | 391 | } 392 | 393 | /** 394 | * Get the object for the specified stone 395 | * @param $name 396 | * @throws Exception 397 | */ 398 | public function get($name= null) { 399 | 400 | if ( $name === null ) throw new Exception('Object name must be specified.'); 401 | if ( $name instanceof substrate_ContextStoneReference ) { 402 | $name = $name->name(); 403 | } 404 | 405 | if ( $this->initialized($name) ) { 406 | return isset($this->stoneInstances[$name]) ? $this->stoneInstances[$name] : null; 407 | } 408 | 409 | $this->initializedStones[$name] = true; 410 | 411 | if ( ! isset($this->preparedStones[$name]) ) { 412 | // TODO: This is not DRY. See execute() 413 | $stoneDefinition = $this->prepareStone($name); 414 | $this->stoneDefinitions[$name] = $stoneDefinition; 415 | $this->preparedStones[$name] = true; 416 | } 417 | 418 | 419 | $object = $this->instantiate($name); 420 | 421 | // TODO The following should probably be moved to instantiate. 422 | 423 | if ( $object instanceof substrate_stones_IContextAware ) { 424 | $object->informAboutContext($this); 425 | } 426 | 427 | if ( $object instanceof substrate_stones_IContextStartupAware ) { 428 | $object->informAboutContextStartup($this); 429 | } 430 | 431 | return $object; 432 | } 433 | 434 | /** 435 | * Get the definition for a stone by name 436 | * @param $name 437 | */ 438 | public function stoneDefinition($name) { 439 | if ( ! $this->exists($name) ) { 440 | throw new Exception('Could not locate stone definition for name "' . $name . '"'); 441 | } 442 | return $this->stoneDefinitions[$name]; 443 | } 444 | 445 | /** 446 | * Replaced by substrate_Context::stoneDefinition() 447 | * @param $name 448 | * @deprecated 449 | */ 450 | public function getStoneDefinition($name) { 451 | return $this->deprecated()->stoneDefinition($name); 452 | } 453 | 454 | /** 455 | * @see substrate_IContext::registeredStoneNames() 456 | * @override 457 | */ 458 | public function registeredStoneNames() { 459 | return array_keys($this->stoneDefinitions); 460 | } 461 | 462 | /** 463 | * Replaced by substrate_Context::registeredStoneNames() 464 | * @deprecated 465 | */ 466 | public function getRegisteredStoneNames() { 467 | return $this->deprecated()->registeredStoneNames(); 468 | } 469 | 470 | /** 471 | * Replaced by substrate_Context::registeredStoneNames() 472 | * @deprecated 473 | */ 474 | public function getRegisteredObjectNames() { 475 | return $this->deprecated()->registeredStoneNames(); 476 | } 477 | 478 | /** 479 | * Reference a stone 480 | * @param $name 481 | */ 482 | public function ref($name = null) { 483 | if ( $name === null ) throw new Exception('Stone name must be specified.'); 484 | return new substrate_ContextStoneReference($name); 485 | } 486 | 487 | /** 488 | * Generate an anonymous stone name 489 | * @return string 490 | */ 491 | protected final function generateAnonymousStoneName() { 492 | if ( ! isset($this->anonymousStoneNameCounter) ) { 493 | $this->anonymousStoneNameCounter = 0; 494 | } 495 | return '___anonymousStone_context' . $this->id . '_stone' . $this->anonymousStoneNameCounter++; 496 | } 497 | 498 | /** 499 | * Generate an anonymous stone name 500 | * @return string 501 | * @deprecated 502 | */ 503 | protected final function generateAnonymousObjectName() { 504 | return $this->deprecated()->generateAnonymousStoneName(); 505 | } 506 | 507 | /** 508 | * Add a new stone to the context 509 | * 510 | * $context->add('foo', 'my_Foo'); 511 | * $context->add('foo', array('className' => 'my_Foo')); 512 | * $context->add(array('name' => 'foo', 'className' => 'my_Foo')); 513 | * 514 | * @throws Exception 515 | */ 516 | public function add() { 517 | $name = null; 518 | $setup = null; 519 | $args = func_get_args(); 520 | if ( count($args) == 2 ) { 521 | list($name, $setup) = $args; 522 | } else { 523 | $name = $this->generateAnonymousStoneName(); 524 | list($setup) = $args; 525 | } 526 | if ( $setup === null ) throw new Exception('Setup cannot be null.'); 527 | if ( ! is_array($setup) ) { 528 | $setup = array ('className' => $setup); 529 | } 530 | $setup['name'] = $name; 531 | if ( ! isset($setup['includeFilename']) ) $setup['includeFilename'] = null; 532 | if ( ! isset($setup['abstract']) ) $setup['abstract'] = false; 533 | if ( ! isset($setup['parent']) ) $setup['parent'] = null; 534 | if ( ! isset($setup['properties']) ) $setup['properties'] = array(); 535 | if ( ! isset($setup['constructorArgs']) ) $setup['constructorArgs'] = array(); 536 | if ( ! isset($setup['dependencies']) ) $setup['dependencies'] = array(); 537 | if ( ! isset($setup['inheritConstructorArgs']) ) $setup['inheritConstructorArgs'] = true; 538 | if ( ! isset($setup['lazyLoad']) ) $setup['lazyLoad'] = true; 539 | if ( ! isset($setup['className']) ) $setup['className'] = null; 540 | $this->stoneDefinitions[$name] = $setup; 541 | return new substrate_ContextStoneReference($name); 542 | } 543 | 544 | /** 545 | * Set a stone in the context 546 | * 547 | * Alias for substrate_Context::add() 548 | * @see substrate_Context::add() 549 | */ 550 | public function set() { 551 | $args = func_get_args(); 552 | return call_user_func_array(array($this, 'add'), $args); 553 | } 554 | 555 | /** 556 | * Prepare a stone by name 557 | * 558 | * Preparing a stone essentially traverses the parents to ensure that 559 | * the stone's settings are correct. 560 | * 561 | * @param $name 562 | * @return array 563 | */ 564 | protected function prepareStone($name) { 565 | 566 | $returnSetup = $thisStoneSetup = $this->stoneDefinitions[$name]; 567 | 568 | if ( $thisStoneSetup['parent'] ) { 569 | $returnSetup = $this->prepareStone($thisStoneSetup['parent']); 570 | } 571 | 572 | foreach ( $thisStoneSetup as $param => $value ) { 573 | if ( $param == 'properties' ) { 574 | $returnSetup[$param] = array_merge($returnSetup[$param], $value); 575 | } elseif ( $param == 'dependencies' ) { 576 | $returnSetup[$param] = array_merge($returnSetup[$param], $value); 577 | } elseif ( $param == 'constructorArgs' ) { 578 | if ( $returnSetup['inheritConstructorArgs'] and $thisStoneSetup['parent']) { 579 | foreach ( $thisStoneSetup['constructorArgs'] as $constructorArg => $constructorValue ) { 580 | $returnSetup[$param][$constructorArg] = $constructorValue; 581 | } 582 | } else { 583 | $returnSetup[$param] = $value; 584 | } 585 | } elseif ( $param == 'className' and $value === null) { 586 | $returnSetup[$param] = $returnSetup[$param]; 587 | } else { 588 | $returnSetup[$param] = $value; 589 | } 590 | } 591 | 592 | foreach ( array('constructorArgs', 'properties', 'dependencies') as $key ) { 593 | foreach ( $returnSetup[$key] as $i => $value ) { 594 | $returnSetup[$key][$i] = $this->replacePlaceholder($value); 595 | } 596 | } 597 | 598 | return $returnSetup; 599 | 600 | } 601 | 602 | /** 603 | * Load dependant classes based on a specified setup 604 | * @param $setup 605 | */ 606 | protected function loadDependantClasses($setup) { 607 | if ( $setup['parent'] ) { 608 | $this->loadDependantClasses($this->stoneDefinitions[$setup['parent']]); 609 | } 610 | if ( array_key_exists('className', $setup) ) { 611 | $this->loadClass($setup['className'], $setup['includeFilename']); 612 | } 613 | } 614 | 615 | /** 616 | * Load a class 617 | * @param $className 618 | * @param $includeFilename 619 | */ 620 | protected function loadClass($className, $includeFilename = null) { 621 | if ( $className === null ) throw new Exception('Class name must be specified.'); 622 | if ( class_exists($className) ) return; 623 | $this->classLoader->load($className, $includeFilename); 624 | } 625 | 626 | /** 627 | * Add interface to interface cachemap 628 | * @param $interfaceOrClass 629 | * @param $name 630 | */ 631 | protected function addInterfaceToMap($interfaceOrClass, $name) { 632 | if ( ! isset($this->stoneDefinitionsByInterface[$interfaceOrClass]) ) { 633 | $this->stoneDefinitionsByInterface[$interfaceOrClass] = array(); 634 | } 635 | $this->stoneDefinitionsByInterface[$interfaceOrClass][] = $name; 636 | } 637 | 638 | /** 639 | * Resolve a constructor arg 640 | * @param $value 641 | */ 642 | protected function resolvedConstructorArg($value = null) { 643 | if ( is_object($value) and $value instanceof substrate_ContextStoneReference ) { 644 | return $this->get($value->name()); 645 | } elseif ( is_array($value) ) { 646 | $newArray = array(); 647 | foreach ( $value as $i => $v ) { 648 | $newArray[$i] = $this->resolvedConstructorArg($v); 649 | } 650 | return $newArray; 651 | } 652 | return $value; 653 | } 654 | 655 | /** 656 | * @see substrate_Context::resolvedConstructorArg() 657 | * @deprecated 658 | */ 659 | protected function getResolvedConstructorArg($value = null) { 660 | return $this->deprecated()->resolvedConstructorArg($value); 661 | } 662 | 663 | /** 664 | * Replace a placeholder 665 | * 666 | * This is called when the placeholder is potentially an object, a reference 667 | * or a string. 668 | * 669 | * @param $value 670 | */ 671 | protected function replacePlaceholder($value) { 672 | if ( is_object($value) and $value instanceof substrate_ContextStoneReference ) { 673 | $value->setName($this->replacePlaceholderValue($value->name())); 674 | } else if ( is_array($value) ) { 675 | foreach ( $value as $i => $v ) { 676 | $value[$i] = $this->replacePlaceholder($v); 677 | } 678 | } else if ( is_string($value) ) { 679 | $value = $this->replacePlaceholderValue($value); 680 | } 681 | return $value; 682 | } 683 | 684 | /** 685 | * Replace a placeholder value 686 | * 687 | * This is called when the value is known to be a string. 688 | * 689 | * @param string $value 690 | */ 691 | protected function replacePlaceholderValue($value) { 692 | if ( $this->placeholderConfigurer() !== null ) { 693 | $value = $this->placeholderConfigurer()->replacePlaceholders($value); 694 | } 695 | return $value; 696 | } 697 | 698 | /** 699 | * The placeholder configurer (if defined) 700 | * @return mixed 701 | */ 702 | protected function placeholderConfigurer() { 703 | 704 | if ( $this->exists('placeholderConfigurer') ) { 705 | return $this->get('placeholderConfigurer'); 706 | } 707 | 708 | return null; 709 | 710 | } 711 | 712 | /** 713 | * Load references for a stone. 714 | * @param $name 715 | * @param $references 716 | */ 717 | private function loadReferences($name, $references) { 718 | $stone = $this->stoneInstances[$name]; 719 | foreach ( $references as $reference ) { 720 | $methodName = $reference['methodName']; 721 | $contextStoneReference = $reference['contextStoneReference']; 722 | if ( $contextStoneReference instanceof substrate_ContextStoneReference ) { 723 | $referencedStone = $this->get($contextStoneReference->name()); 724 | } else { 725 | $referencedStone = $this->get($contextStoneReference); 726 | } 727 | if ( $methodName !== null ) { 728 | $stone->$methodName($referencedStone); 729 | } 730 | } 731 | } 732 | 733 | /** 734 | * Find all stones by an implementation 735 | * @param $classOrInterface 736 | */ 737 | public function findStonesByImplementation($classOrInterface) { 738 | 739 | if ( ! isset($this->stoneDefinitionsByInterface[$classOrInterface])) { 740 | return array(); 741 | } 742 | 743 | $stones = array(); 744 | foreach ( $this->stoneDefinitionsByInterface[$classOrInterface] as $name ) { 745 | $stones[] = $this->get($name); 746 | } 747 | return $stones; 748 | 749 | } 750 | 751 | /** 752 | * @see substrate_Context::placeholderConfigurer() 753 | * @deprecated 754 | */ 755 | protected function getPlaceholderConfigurer() { 756 | return $this->deprecated()->placeholderConfigurer(); 757 | } 758 | 759 | /** 760 | * Initialize logging 761 | */ 762 | protected function initializeLogging() { 763 | if ( ! $this->loggingInitialized ) { 764 | $this->loggingInitialized = true; 765 | if ( $this->exists('logFactory') ) { 766 | $this->logger = $this->get('logFactory')->get(); 767 | } elseif ( $this->exists('logger') ) { 768 | $this->logger = $this->get('logger'); 769 | } 770 | if ( $this->logger !== null ) { 771 | foreach ( $this->logMessages as $message ) { 772 | $this->log($message[0], $message[1]); 773 | } 774 | $this->logMessages = null; 775 | set_error_handler(array($this->logger, 'handleError')); 776 | set_exception_handler(array($this->logger, 'handleException')); 777 | } 778 | } 779 | } 780 | 781 | /** 782 | * Log 783 | * @param string $type 784 | * @param string $message 785 | */ 786 | private function log($type, $message = null) { 787 | if ( $this->loggingInitialized ) { 788 | if ( $this->logger !== null ) { 789 | $this->logger->$type($message); 790 | } 791 | } else { 792 | $this->logMessages[] = array($type, $message); 793 | } 794 | } 795 | 796 | /** 797 | * Log trace message 798 | * @param string $message 799 | */ 800 | protected function logTrace($message = null) { 801 | $this->log('trace', $message); 802 | } 803 | 804 | /** 805 | * Log debug message 806 | * @param string $message 807 | */ 808 | protected function logDebug($message = null) { 809 | $this->log('debug', $message); 810 | } 811 | 812 | /** 813 | * Log info message 814 | * @param string $message 815 | */ 816 | protected function logInfo($message = null) { 817 | $this->log('info', $message); 818 | } 819 | 820 | /** 821 | * Log warn message 822 | * @param string $message 823 | */ 824 | protected function logWarn($message = null) { 825 | $this->log('warn', $message); 826 | } 827 | 828 | /** 829 | * Log error message 830 | * @param string $message 831 | */ 832 | protected function logError($message = null) { 833 | $this->log('error', $message); 834 | } 835 | 836 | /** 837 | * Log fatal message 838 | * @param string $message 839 | */ 840 | protected function logFatal($message = null) { 841 | $this->log('fatal', $message); 842 | } 843 | 844 | /** 845 | * Used to notify about a deprecated call 846 | */ 847 | protected function deprecated() { 848 | $back = debug_backtrace(); 849 | $this->logWarn('Deprecated call to ' . $back[1]['class'] . '::' . $back[1]['function'] . ', ' . $back[1]['file'] . ':' . $back[1]['line']); 850 | return $this; 851 | } 852 | 853 | } 854 | 855 | ?> 856 | --------------------------------------------------------------------------------