Ticket #523: bindings.patch
| File bindings.patch, 14.6 kB (added by doubleface, 2 years ago) |
|---|
-
build/manifests/jelix-lib.mn
265 265 cd lib/jelix/utils/ 266 266 jAppManager.class.php 267 267 jClasses.class.php 268 jBinding.class.php 268 269 jCmdUtils.class.php 269 270 jCrypt.class.php 270 271 jDatatype.class.php -
build/manifests/testapp.mn
1 1 cd testapp 2 2 3 project.xml 3 4 .htaccess 4 5 application.init.php … … 81 82 cd testapp/modules/jelix_tests/classes/tests 82 83 foo.class.php 83 84 foo.iface.php 85 bind.class.php 84 86 cd testapp/modules/jelix_tests/locales/ 85 87 test_A.properties 86 88 test_B.properties … … 163 165 utils.jlog.html_cli.php 164 166 utils.jdatetime.html_cli.php 165 167 utils.jinifilemodifier.html_cli.php 168 utils.jclasses.html_cli.php 166 169 167 170 cd testapp/var 168 171 .htaccess -
testapp/modules/jelix_tests/tests/utils.jclasses.html_cli.php
1 <?php 2 /** 3 * @package testapp 4 * @subpackage jelix_tests module 5 * @author Thiriot Christophe 6 * @contributor 7 * @copyright 2008 Thiriot Christophe 8 * @link http://www.jelix.org 9 * @licence GNU Lesser General Public Licence see LICENCE file or http://www.gnu.org/licenses/lgpl.html 10 */ 11 12 class UTjclasses extends UnitTestCase { 13 14 public function setUp() { 15 jClasses::resetBindings(); 16 } 17 18 public function testClassNoBinding() { 19 $this->assertTrue(class_exists('jBinding')); 20 $class = jClasses::getBindedService('class:jelix_tests~myclass'); 21 $this->assertTrue($class instanceof myclass); 22 23 // same test with an interface (raises an exception) 24 try { 25 $class = jClasses::getBindedService('iface:jelix_tests~test'); 26 $this->fail('An interface without binding should raise an exception'); 27 } catch (jExceptionSelector $e) { 28 $this->pass(); 29 } 30 } 31 32 public function testBindingInCodeTo() { 33 jClasses::bind('jelix_tests~test')->to('jelix_tests~myclass'); 34 $class = jClasses::getBindedService('jelix_tests~test'); 35 $this->assertTrue($class instanceof myclass); 36 37 jClasses::bind('jelix_tests~test')->to('jelix_tests~myclass'); 38 $classname = jClasses::getBinding('jelix_tests~test')->getClassName(); 39 $this->assertTrue($classname === 'myclass'); 40 41 try { 42 jClasses::bind('jelix_tests~test')->to('jelix_tests~notexistingclass'); 43 $this->fail('A binding to a non existing class should raise an exception'); 44 } catch (jExceptionSelector $e) { 45 $this->pass(); 46 } 47 } 48 49 public function testBindingInCodeToInstance() { 50 $instance = jClasses::create('jelix_tests~myclass'); 51 jClasses::bind('jelix_tests~test')->toInstance($instance); 52 $class = jClasses::getBindedService('jelix_tests~test'); 53 $this->assertTrue($class instanceof myclass); 54 55 jClasses::bind('jelix_tests~test')->toInstance($instance); 56 $classname = jClasses::getBinding('jelix_tests~test')->getClassName(); 57 $this->assertTrue($classname === 'myclass'); 58 } 59 60 // test with binding in jelix config file + get class name + non existing binded class 61 public function testBindingInJelixConfigFile() { 62 global $gJConfig; 63 $oldgjconfig = clone $gJConfig; 64 65 $gJConfig->{jBinding::BINDINGS_CONFIG_SECTION}['jelix_tests*test'] = 'jelix_tests~myclass'; 66 $class = jClasses::getBindedService('jelix_tests~test'); 67 $this->assertTrue($class instanceof myclass); 68 69 // test with long selector and test with parse_ini_file 70 $gJConfig->{jBinding::BINDINGS_CONFIG_SECTION}['class:jelix_tests*myclass'] = 'jelix_tests~myclass'; 71 $class = jClasses::getBindedService('class:jelix_tests~myclass'); 72 $this->assertTrue($class instanceof myclass); 73 74 $gJConfig = $oldgjconfig; 75 } 76 77 // test with binding in DEFAULT IMPLEMENTATION constant + get class name + non existing binded class 78 public function testBindingInDefaultImplementation() { 79 $classname = jClasses::getBinding('iface:jelix_tests~tests/foo')->getClassName(); 80 $this->assertEqual($classname, 'bind'); 81 jClasses::resetBindings(); 82 83 $class = jClasses::getBindedService('iface:jelix_tests~tests/foo'); 84 $this->assertTrue($class instanceof bind); 85 86 jClasses::resetBindings(); 87 88 try { 89 $class = jClasses::getBindedService('class:jelix_tests~test/bind'); 90 $this->fail('A non existing default implementation should raise an exception'); 91 } catch (jExceptionSelector $e) { 92 $this->pass(); 93 } 94 } 95 } 96 97 ?> -
testapp/modules/jelix_tests/classes/tests/foo.iface.php
1 1 <?php 2 2 3 3 interface foo { 4 4 const JBINDING_BINDED_IMPLEMENTATION = 'jelix_tests~tests/bind'; 5 5 } 6 6 7 ?> 8 Pas de fin de ligne à la fin du fichier 7 ?> -
testapp/modules/jelix_tests/classes/tests/bind.class.php
1 <?php 2 3 class bind { 4 const JBINDING_BINDED_IMPLEMENTATION = 'jelix_tests~nonexistingclass'; 5 } 6 7 ?> -
lib/jelix/core/jSelector.class.php
34 34 * @param string $selstr the selector. It should be a full selector : "type:module~resource" (not "module~resource") 35 35 * @return jISelector the corresponding selector 36 36 */ 37 static public function create ($selstr){ 37 static public function create ($selstr, $defaulttype=false){ 38 if (is_string($defaulttype) && strpos($selstr, ':') === false) { 39 $selstr = "$defaulttype:$selstr"; 40 } 41 38 42 if(preg_match("/^([a-z]{3,5})\:([\w~\/\.]+)$/", $selstr, $m)){ 39 43 $cname='jSelector'.$m[1]; 40 44 if(class_exists($cname)){ -
lib/jelix/utils/jClasses.class.php
19 19 20 20 static protected $_instances = array(); 21 21 22 static protected $_bindings = array(); 23 22 24 private function __construct(){} 23 25 24 26 /** … … 60 62 } 61 63 62 64 /** 65 * Shortcut to corresponding jBinding::getInstance() 66 * 67 * @param string $selector Selector to a bindable class|interface 68 * @return mixed Corresponding instance 69 */ 70 static public function getBindedService($selector){ 71 return self::getBinding($selector)->getInstance(); 72 } 73 74 /** 75 * Alias of self::getBinding method. Better for use like this : jClasses::bind('selector').to('classselector') 76 * 77 * @param string $selector 78 * @return jBinding 79 * @see jClasses::bind 80 */ 81 static public function bind($selector) { 82 return self::getBinding($selector); 83 } 84 85 /** 86 * Get the binding corresponding to the specified selector. 87 * Better for use like this : jClasses::getBinding($selector)->getClassName() 88 * 89 * @param string $selector 90 * @return jBinding 91 * @see jClasses::bind 92 */ 93 static public function getBinding($selector) { 94 $osel = jSelectorFactory::create($selector, 'iface'); 95 $s = $osel->toString(true); 96 97 if (!isset(self::$_bindings[$s])) { 98 self::$_bindings[$s] = new jBinding($osel); 99 } 100 101 return self::$_bindings[$s]; 102 } 103 104 /** 105 * Reset the defined bindings (should only use it for unit tests) 106 * 107 * @return void 108 */ 109 static public function resetBindings() { 110 self::$_bindings = array(); 111 } 112 113 /** 63 114 * only include a class 64 115 * @param string $selector the jelix selector correponding to the class 65 116 */ -
lib/jelix/utils/jBinding.class.php
1 <?php 2 /** 3 * @package jelix 4 * @subpackage utils 5 * @author Christophe THIRIOT 6 * @copyright 2008 Christophe THIRIOT 7 * @link http://www.jelix.org 8 * @licence GNU Lesser General Public Licence see LICENCE file or http://www.gnu.org/licenses/lgpl.html 9 */ 10 11 /** 12 * Services binding for jelix 13 * 14 * @package jelix 15 * @subpackage utils 16 */ 17 class jBinding 18 { 19 /** 20 * Section in the jelix config file where bindings are specified 21 */ 22 const BINDINGS_CONFIG_SECTION = 'Bindings'; 23 24 /** 25 * Name of the constant setting the default binded implementation 26 */ 27 const BINDED_IMPLEMENTATION_LABEL = 'JBINDING_BINDED_IMPLEMENTATION'; 28 29 /** 30 * Jelix selector separator in code 31 */ 32 const CODE_SELECTOR_SEPARATOR = '~'; 33 34 /** 35 * Jelix selector separator in jelix config file 36 */ 37 const CONFIG_SELECTOR_SEPARATOR = '*'; 38 39 /** 40 * @var jSelectorInterface|jSelectorClass Called selector 41 */ 42 protected $fromselector = null; 43 44 /** 45 * selector to the binded class (string form) 46 */ 47 protected $toselector = null; 48 49 /** 50 * resulting binded instance 51 */ 52 protected $instance = null; 53 54 /** 55 * __constructor 56 * @param jSelectorInterface|jSelectorClass 57 * @return void 58 */ 59 public function __construct($selector) { 60 require_once($selector->getPath()); 61 $this->fromselector = $selector; 62 } 63 64 /** 65 * Bind the selector to the class specified 66 * Even if this instance is already defined (BE CAREFUL !!! singleton is bypassed) 67 * 68 * @param string $toselector 69 * @return jBinding $this 70 */ 71 public function to($toselector) { 72 $this->toselector = new jSelectorClass($toselector); 73 $this->instance = null; 74 return $this; 75 } 76 77 /** 78 * Bind the selector to the specified instance 79 * Even if this instance is already defined (BE CAREFUL !!! singleton is bypassed) 80 * 81 * @param mixed $instance 82 * @return jBinding $this 83 */ 84 public function toInstance($instance) { 85 $this->instance = $instance; 86 $this->toselector = null; 87 return $this; 88 } 89 90 /** 91 * Get the binded instance 92 * 93 * @return mixed 94 */ 95 public function getInstance() { 96 if ($this->instance === null){ 97 if ($this->toselector === null) { 98 $this->toselector = $this->_getClassSelector(); 99 } 100 $this->instance = jClasses::create($this->toselector->toString()); 101 } 102 return $this->instance; 103 } 104 105 /** 106 * Get the name of the binded class without creating this class 107 * 108 * @return string 109 */ 110 public function getClassName() { 111 $class_name = null; 112 if ($this->instance !== null) { 113 $class_name = get_class($this->instance); 114 } elseif ($this->toselector !== null) { 115 $class_name = $this->toselector->className; 116 } else { 117 $class_name = $this->_getClassSelector()->className; 118 } 119 return $class_name; 120 } 121 122 /** 123 * Get the selector to the binded class 124 * Protected because this does not work if called after a simple __construct() and a toInstance() 125 * 126 * @return string 127 */ 128 protected function _getClassSelector() { 129 $class_selector = null; 130 131 // the instance is not already created 132 if ($this->toselector === null && $this->instance === null) { 133 $str_selector = $this->fromselector->toString(); 134 $str_selector_long = $this->fromselector->toString(true); 135 136 // 1) verify that a default implementation is specified in the jelix config file 137 global $gJConfig; 138 if (isset($gJConfig->{self::BINDINGS_CONFIG_SECTION})) { 139 $conf = $gJConfig->{self::BINDINGS_CONFIG_SECTION}; 140 141 // No '~' allowed as key of a ini file, we use '*' instead 142 $conf_selector = str_replace(self::CODE_SELECTOR_SEPARATOR, self::CONFIG_SELECTOR_SEPARATOR, $str_selector); 143 $conf_selector_long = str_replace(self::CODE_SELECTOR_SEPARATOR, self::CONFIG_SELECTOR_SEPARATOR, $str_selector_long); 144 // get the binding corresponding to selctor, long or not 145 $str_fromselector = null; 146 if (isset($conf[$conf_selector])) { 147 $str_fromselector = $conf_selector; 148 } elseif (isset($conf[$conf_selector_long])){ 149 $str_fromselector = $conf_selector_long; 150 } 151 152 if ($str_fromselector !== null) { 153 $this->fromselector = jSelectorFactory::create($str_selector_long, 'interface'); 154 return $this->toselector = new jSelectorClass($conf[$str_fromselector]); 155 } 156 } 157 158 // 2) see if a default implementation is specified in the source class 159 $class_selector = @constant($this->fromselector->className . '::' . jBinding::BINDED_IMPLEMENTATION_LABEL); 160 if ($class_selector!==null) return $this->toselector = new jSelectorClass($class_selector); 161 162 // 3) If the source is a class, then use it as the default implementation 163 if ($this->fromselector instanceof jSelectorClass) { 164 return $this->toselector = new jSelectorClass($str_selector); 165 } 166 167 // TODO add this locale in jelix locales 168 throw new jException('jelix~errors.binding.nobinding', array($this->fromselector->toString(true))); 169 } 170 } 171 } 172 ?>
