Skip to content
Permalink
Browse files

Implement hasMethod() and call()

Expand the ObjectRegistry::_create interface to include the alias of
the object being built. This allows BehaviorRegistry to use this
information to build method caches. Update all the various
implementations around the framework as well.
  • Loading branch information...
markstory committed Oct 23, 2013
1 parent 8b9f916 commit 6fa2d9decda2643a91203d9777180e6af4d82730
@@ -59,12 +59,13 @@ protected function _throwMissingClassError($class, $plugin) {
*
* Part of the template method for Cake\Utility\ObjectRegistry::load()
* @param string|CacheEngine $class The classname or object to make.
* @param string $alias The alias of the object.
* @param array $settings An array of settings to use for the cache engine.
* @return CacheEngine The constructed CacheEngine class.
* @throws Cake\Error\Exception when an object doesn't implement
* the correct interface.
*/
protected function _create($class, $settings) {
protected function _create($class, $alias, $settings) {
if (is_object($class)) {
$instance = $class;
}
@@ -73,11 +73,12 @@ protected function _throwMissingClassError($class, $plugin) {
*
* Part of the template method for Cake\Utility\ObjectRegistry::load()
*
* @param string $class The classname that is missing.
* @param string $class The classname to create.
* @param string $alias The alias of the task.
* @param array $settings An array of settings to use for the task.
* @return Component The constructed task class.
*/
protected function _create($class, $settings) {
protected function _create($class, $alias, $settings) {
return new $class(
$this->_Shell->stdout,
$this->_Shell->stderr,
@@ -98,11 +98,12 @@ protected function _throwMissingClassError($class, $plugin) {
* Part of the template method for Cake\Utility\ObjectRegistry::load()
* Enabled components will be registered with the event manager.
*
* @param string $class The classname that is missing.
* @param string $class The classname to create.
* @param string $alias The alias of the component.
* @param array $settings An array of settings to use for the component.
* @return Component The constructed component class.
*/
protected function _create($class, $settings) {
protected function _create($class, $alias, $settings) {
$instance = new $class($this, $settings);
$enable = isset($settings['enabled']) ? $settings['enabled'] : true;
if ($enable) {
@@ -66,10 +66,11 @@ protected function _throwMissingClassError($class, $plugin) {
* Part of the template method for Cake\Utility\ObjectRegistry::load()
*
* @param string|Driver $class The classname or object to make.
* @param string $alias The alias of the object.
* @param array $settings An array of settings to use for the driver.
* @return Connection A connection with the correct driver.
*/
protected function _create($class, $settings) {
protected function _create($class, $alias, $settings) {
if (is_object($class)) {
$instance = $class;
}
@@ -58,12 +58,13 @@ protected function _throwMissingClassError($class, $plugin) {
*
* Part of the template method for Cake\Utility\ObjectRegistry::load()
* @param string|LogInterface $class The classname or object to make.
* @param string $alias The alias of the object.
* @param array $settings An array of settings to use for the logger.
* @return LogEngine The constructed logger class.
* @throws Cake\Error\Exception when an object doesn't implement
* the correct interface.
*/
protected function _create($class, $settings) {
protected function _create($class, $alias, $settings) {
if (is_object($class)) {
$instance = $class;
}
@@ -16,6 +16,7 @@
use Cake\Core\App;
use Cake\Error;
use Cake\ORM\Behavior;
use Cake\ORM\Table;
use Cake\Utility\ObjectRegistry;
@@ -43,6 +44,13 @@ class BehaviorRegistry extends ObjectRegistry {
*/
protected $_eventManager;
/**
* Method mappings.
*
* @var array
*/
protected $_methodMap = [];
/**
* Constructor
*
@@ -88,15 +96,47 @@ protected function _throwMissingClassError($class, $plugin) {
* Enabled behaviors will be registered with the event manager.
*
* @param string $class The classname that is missing.
* @param string $alias The alias of the object.
* @param array $settings An array of settings to use for the behavior.
* @return Component The constructed behavior class.
*/
protected function _create($class, $settings) {
protected function _create($class, $alias, $settings) {
$instance = new $class($this->_table, $settings);
$enable = isset($settings['enabled']) ? $settings['enabled'] : true;
if ($enable) {
$this->_eventManager->attach($instance);
}
$this->_mapMethods($instance, $class, $alias);
return $instance;
}
/**
* Store the map of behavior methods and ensure there are no duplicates.
*
* Use the implementedEvents() method to exclude callback methods.
*
* @param Cake\ORM\Behavior $instance
* @return void
*/
protected function _mapMethods(Behavior $instance, $class, $alias) {
$events = $instance->implementedEvents();
$methods = get_class_methods($instance);
foreach ($events as $e => $binding) {
if (is_array($binding) && isset($binding['callable']) && isset($binding['callable'])) {
$binding = $binding['callable'];
}
$index = array_search($binding, $methods);
unset($methods[$index]);
}
foreach ($methods as $method) {
if (isset($this->_methodMap[$method])) {
$message = '%s contains duplicate method "%s" which is already provided by %s';
$error = __d('cake_dev', $message, $class, $method, $this->_methodMap[$method]);
throw new Error\Exception($error);
}
$this->_methodMap[$method] = $alias;
}
return $instance;
}
@@ -110,17 +150,22 @@ protected function _create($class, $settings) {
* @return boolean
*/
public function hasMethod($method) {
return isset($this->_methodMap[$method]);
}
/**
* Invoke a method on a behavior.
*
* @param string $method The method to invoke.
* @param mixed $args The arguments you want to invoke the method with should
* be provided as the remaining arguments to call()
* @param array $args The arguments you want to invoke the method with.
* @return mixed The return value depends on the underlying behavior method.
*/
public function call($method) {
public function call($method, array $args = []) {
if (!$this->hasMethod($method)) {
return false;
}
$alias = $this->_methodMap[$method];
return call_user_func_array([$this->_loaded[$alias], $method], $args);
}
}
@@ -35,7 +35,7 @@ public function findNoSlug(Query $query, $options = []) {
return $query;
}
public function slugify(Table $table, $value) {
public function slugify($value) {
return Inflector::slug($value);
}
@@ -55,7 +55,7 @@ public function tearDown() {
* @return void
*/
public function testLoad() {
$settings = ['replacement' => '-'];
$settings = ['alias' => 'Sluggable', 'replacement' => '-'];
$result = $this->Behaviors->load('Sluggable', $settings);
$this->assertInstanceOf('TestApp\Model\Behavior\SluggableBehavior', $result);
$this->assertEquals($settings, $result->settings);
@@ -114,7 +114,7 @@ public function testLoadMissingClass() {
* Test load() duplicate method error
*
* @expectedException Cake\Error\Exception
* @expectedExceptionMessage TestApp\Model\Behavior\DuplicateBehavior contains duplicate method "dupe"
* @expectedExceptionMessage TestApp\Model\Behavior\DuplicateBehavior contains duplicate method "slugify"
* @return void
*/
public function testLoadDuplicateMethodError() {
@@ -140,7 +140,10 @@ public function testHasMethod() {
*/
public function testCall() {
$this->Behaviors->load('Sluggable');
$result = $this->Behaviors->call('slugify', 'some value');
$result = $this->Behaviors->call('nope');
$this->assertFalse($result);
$result = $this->Behaviors->call('slugify', ['some value']);
$this->assertEquals('some_value', $result);
}
@@ -75,7 +75,7 @@ public function load($objectName, $settings = []) {
if (!$className) {
$this->_throwMissingClassError($objectName, substr($plugin, 0, -1));
}
$instance = $this->_create($className, $settings);
$instance = $this->_create($className, $name, $settings);
$this->_loaded[$name] = $instance;
return $instance;
}
@@ -104,10 +104,11 @@ public function load($objectName, $settings = []) {
* required.
*
* @param string $class The class to build.
* @param string $alias The alias of the object.
* @param array $settings The settings for construction
* @return mixed
*/
abstract protected function _create($class, $settings);
abstract protected function _create($class, $alias, $settings);
/**
* Get the loaded object list, or get the object instance at a given name.
@@ -133,11 +133,12 @@ protected function _throwMissingClassError($class, $plugin) {
* Part of the template method for Cake\Utility\ObjectRegistry::load()
* Enabled helpers will be registered with the event manager.
*
* @param string $class The classname that is missing.
* @param string $class The class to create.
* @param string $alias The alias of the loaded helper.
* @param array $settings An array of settings to use for the helper.
* @return Component The constructed helper class.
*/
protected function _create($class, $settings) {
protected function _create($class, $alias, $settings) {
$instance = new $class($this->_View, $settings);
$vars = array('request', 'theme', 'plugin');
foreach ($vars as $var) {

0 comments on commit 6fa2d9d

Please sign in to comment.
You can’t perform that action at this time.