Permalink
Browse files

Implement `respondsTo()` for static and magic method detection.

  • Loading branch information...
Blaine Schmeisser
Blaine Schmeisser committed Feb 1, 2013
1 parent 6a5691c commit d17172b746fa9c2c87186d507cba79b525317b20
Showing with 529 additions and 5 deletions.
  1. +16 −0 analysis/Inspector.php
  2. +11 −0 analysis/Logger.php
  3. +12 −0 core/Object.php
  4. +12 −0 core/StaticObject.php
  5. +22 −0 data/Entity.php
  6. +17 −0 data/Model.php
  7. +11 −0 data/model/Query.php
  8. +11 −0 data/model/Relationship.php
  9. +11 −0 data/source/Http.php
  10. +12 −0 data/source/MongoDb.php
  11. +12 −0 data/source/http/adapter/CouchDb.php
  12. +11 −0 g11n/Locale.php
  13. +11 −0 net/http/Service.php
  14. +12 −0 storage/cache/adapter/Redis.php
  15. +11 −0 template/helper/Form.php
  16. +11 −0 template/view/Renderer.php
  17. +12 −0 test/MockerChain.php
  18. +38 −2 tests/cases/analysis/InspectorTest.php
  19. +12 −0 tests/cases/analysis/LoggerTest.php
  20. +12 −0 tests/cases/core/ObjectTest.php
  21. +10 −0 tests/cases/core/StaticObjectTest.php
  22. +22 −0 tests/cases/data/EntityTest.php
  23. +20 −0 tests/cases/data/ModelTest.php
  24. +7 −0 tests/cases/data/model/QueryTest.php
  25. +23 −0 tests/cases/data/model/RelationshipTest.php
  26. +14 −0 tests/cases/data/source/HttpTest.php
  27. +20 −0 tests/cases/data/source/MongoDbTest.php
  28. +7 −0 tests/cases/data/source/http/adapter/CouchDbTest.php
  29. +12 −0 tests/cases/g11n/LocaleTest.php
  30. +7 −0 tests/cases/net/http/ServiceTest.php
  31. +12 −0 tests/cases/storage/cache/adapter/RedisTest.php
  32. +6 −0 tests/cases/template/helper/FormTest.php
  33. +6 −0 tests/cases/template/view/RendererTest.php
  34. +13 −0 tests/cases/test/MockerChainTest.php
  35. +5 −3 tests/cases/test/filter/ComplexityTest.php
  36. +22 −0 tests/cases/util/CollectionTest.php
  37. +12 −0 tests/cases/util/ValidatorTest.php
  38. +4 −0 tests/mocks/core/MockStaticInstantiator.php
  39. +5 −0 tests/mocks/data/MockPost.php
  40. +12 −0 util/Collection.php
  41. +13 −0 util/Validator.php
View
@@ -48,6 +48,22 @@ class Inspector extends \lithium\core\StaticObject {
'shortName' => 'getShortName'
);
+ /**
+ * Will determine if a method can be called.
+ *
+ * @param string|object $class Class to inspect.
+ * @param string $method Method name.
+ * @param bool $internal Interal call or not.
+ * @return bool
+ */
+ public static function isCallable($object, $method, $internal = false) {
+ $methodExists = method_exists($object, $method);
+ $callable = function($object, $method) {
+ return is_callable(array($object, $method));
+ };
+ return $internal ? $methodExists : $methodExists && $callable($object, $method);
+ }
+
/**
* Determines if a given $identifier is a class property, a class method, a class itself,
* or a namespace identifier.
View
@@ -139,6 +139,17 @@ public static function __callStatic($priority, $params) {
return static::write($priority, $params[0], $params[1]);
}
+ /**
+ * Custom check to determine if our given magic methods can be responded to.
+ *
+ * @param string $method Method name.
+ * @param bool $internal Interal call or not.
+ * @return bool
+ */
+ public static function respondsTo($method, $internal = false) {
+ return isset(static::$_priorities[$method]) || parent::respondsTo($method, $internal);
+ }
+
/**
* This method is called automatically to initialize the default configuration of a log adapter,
* such that the adapter defaults to accepting log messages of any priority (i.e. the
View
@@ -10,6 +10,7 @@
use lithium\core\Libraries;
use lithium\util\collection\Filters;
+use lithium\analysis\Inspector;
/**
* Base class in Lithium's hierarchy, from which all concrete classes inherit. This class defines
@@ -205,6 +206,17 @@ public static function __set_state($data) {
return $object;
}
+ /**
+ * Will determine if a method can be called.
+ *
+ * @param string $method Method name.
+ * @param bool $internal Interal call or not.
+ * @return bool
+ */
+ public function respondsTo($method, $internal = false) {
+ return Inspector::isCallable($this, $method, $internal);
+ }
+
/**
* Returns an instance of a class with given `config`. The `name` could be a key from the
* `classes` array, a fully-namespaced class name, or an object. Typically this method is used
View
@@ -10,6 +10,7 @@
use lithium\core\Libraries;
use lithium\util\collection\Filters;
+use lithium\analysis\Inspector;
/**
* Provides a base class for all static classes in the Lithium framework. Similar to its
@@ -90,6 +91,17 @@ public static function invokeMethod($method, $params = array()) {
}
}
+ /**
+ * Will determine if a method can be called.
+ *
+ * @param string $method Method name.
+ * @param bool $internal Interal call or not.
+ * @return bool
+ */
+ public static function respondsTo($method, $internal = false) {
+ return Inspector::isCallable(get_called_class(), $method, $internal);
+ }
+
/**
* Returns an instance of a class with given `config`. The `name` could be a key from the
* `classes` array, a fully namespaced class name, or an object. Typically this method is used
View
@@ -11,6 +11,7 @@
use BadMethodCallException;
use UnexpectedValueException;
use lithium\data\Collection;
+use lithium\analysis\Inspector;
/**
* `Entity` is a smart data object which represents data such as a row or document in a
@@ -196,6 +197,27 @@ public function __call($method, $params) {
throw new BadMethodCallException($message);
}
+ /**
+ * Custom check to determine if our given magic methods can be responded to.
+ *
+ * @param string $method Method name.
+ * @param bool $internal Interal call or not.
+ * @return bool
+ */
+ public function respondsTo($method, $internal = false) {
+ $class = $this->_model;
+ $modelRespondsTo = false;
+ $parentRespondsTo = parent::respondsTo($method, $internal);
+ $staticRespondsTo = $class::respondsTo($method, $internal);
+ if (method_exists($class, '_object')) {
+ $model = $class::invokeMethod('_object');
+ $modelRespondsTo = $model->respondsTo($method);
+ } else {
+ $modelRespondsTo = Inspector::isCallable($class, $method, $internal);
+ }
+ return $parentRespondsTo || $staticRespondsTo || $modelRespondsTo;
+ }
+
/**
* Allows several properties to be assigned at once, i.e.:
* {{{
View
@@ -523,6 +523,23 @@ public function __call($method, $params) {
throw new BadMethodCallException($message);
}
+ /**
+ * Custom check to determine if our given magic methods can be responded to.
+ *
+ * @param string $method Method name.
+ * @param bool $internal Interal call or not.
+ * @return bool
+ */
+ public static function respondsTo($method, $internal = false) {
+ $self = static::_object();
+ $methods = static::instanceMethods();
+ $isFinder = isset($self->_finders[$method]);
+ preg_match('/^findBy(?P<field>\w+)$|^find(?P<type>\w+)By(?P<fields>\w+)$/', $method, $args);
+ $staticRepondsTo = $isFinder || $method === 'all' || !!$args;
+ $instanceRespondsTo = isset($methods[$method]);
+ return $instanceRespondsTo || $staticRepondsTo || parent::respondsTo($method, $internal);
+ }
+
/**
* The `find` method allows you to retrieve data from the connected data source.
*
View
@@ -765,6 +765,17 @@ public function __call($method, array $params = array()) {
return isset($this->_config[$method]) ? $this->_config[$method] : null;
}
+ /**
+ * Custom check to determine if our given magic methods can be responded to.
+ *
+ * @param string $method Method name.
+ * @param bool $internal Interal call or not.
+ * @return bool
+ */
+ public function respondsTo($method, $internal = false) {
+ return isset($this->_config[$method]) || parent::respondsTo($method, $internal);
+ }
+
/**
* Will return a find first condition on the associated model if a record is connected.
* Called by conditions when it is called as a get and no condition is set.
@@ -135,6 +135,17 @@ public function __call($name, $args = array()) {
return $this->data($name);
}
+ /**
+ * Custom check to determine if our given magic methods can be responded to.
+ *
+ * @param string $method Method name.
+ * @param bool $internal Interal call or not.
+ * @return bool
+ */
+ public function respondsTo($method, $internal = false) {
+ return is_callable(array($this, $method), true);
+ }
+
protected function _keys($keys) {
$config = $this->_config;
$hasRel = ($related = ($config['type'] == 'belongsTo') ? $config['to'] : $config['from']);
View
@@ -138,6 +138,17 @@ public function __call($method, $params) {
});
}
+ /**
+ * Custom check to determine if our given magic methods can be responded to.
+ *
+ * @param string $method Method name.
+ * @param bool $internal Interal call or not.
+ * @return bool
+ */
+ public function respondsTo($method, $internal = false) {
+ return isset($this->_methods[$method]) || parent::respondsTo($method, $internal);
+ }
+
/**
* Method to send to a specific resource.
*
View
@@ -351,6 +351,18 @@ public function __call($method, $params) {
return call_user_func_array(array(&$this->server, $method), $params);
}
+ /**
+ * Custom check to determine if our given magic methods can be responded to.
+ *
+ * @param string $method Method name.
+ * @param bool $internal Interal call or not.
+ * @return bool
+ */
+ public function respondsTo($method, $internal = false) {
+ $childRespondsTo = is_object($this->server) && is_callable(array($this->server, $method));
+ return parent::respondsTo($method, $internal) || $childRespondsTo;
+ }
+
/**
* Normally used in cases where the query is a raw string (as opposed to a `Query` object),
* to database must determine the correct column names from the result resource. Not
@@ -114,6 +114,18 @@ public function __call($method, $params = array()) {
return json_decode($this->connection->{$method}($path, $data, $options));
}
+ /**
+ * Custom check to determine if our given magic methods can be responded to.
+ *
+ * @param string $method Method name.
+ * @param bool $internal Interal call or not.
+ * @return bool
+ */
+ public function respondsTo($method, $internal = false) {
+ $parentRespondsTo = parent::respondsTo($method, $internal);
+ return $parentRespondsTo || is_callable(array($this->connection, $method));
+ }
+
/**
* Returns an array of object types accessible through this database.
*
View
@@ -81,6 +81,17 @@ public static function __callStatic($method, $params = array()) {
return isset($tags[$method]) ? $tags[$method] : null;
}
+ /**
+ * Custom check to determine if our given magic methods can be responded to.
+ *
+ * @param string $method Method name.
+ * @param bool $internal Interal call or not.
+ * @return bool
+ */
+ public static function respondsTo($method, $internal = false) {
+ return isset(static::$_tags[$method]) || parent::respondsTo($method, $internal);
+ }
+
/**
* Composes a locale from locale tags. This is the pendant to `Locale::decompose()`.
*
View
@@ -115,6 +115,17 @@ public function __call($method, $params = array()) {
return $this->invokeMethod('send', $params);
}
+ /**
+ * Custom check to determine if our given magic methods can be responded to.
+ *
+ * @param string $method Method name.
+ * @param bool $internal Interal call or not.
+ * @return bool
+ */
+ public function respondsTo($method, $internal = false) {
+ return is_callable(array($this, $method), true);
+ }
+
/**
* Send HEAD request.
*
@@ -120,6 +120,18 @@ public function __call($method, $params = array()) {
return call_user_func_array(array(&$this->connection, $method), $params);
}
+ /**
+ * Custom check to determine if our given magic methods can be responded to.
+ *
+ * @param string $method Method name.
+ * @param bool $internal Interal call or not.
+ * @return bool
+ */
+ public function respondsTo($method, $internal = 0) {
+ $parentRespondsTo = parent::respondsTo($method, $internal);
+ return $parentRespondsTo || is_callable(array($this->connection, $method));
+ }
+
/**
* Sets expiration time for cache keys
*
View
@@ -397,6 +397,17 @@ public function __call($type, array $params = array()) {
return $this->_render($type, $template, compact('type', 'name', 'options', 'value'));
}
+ /**
+ * Custom check to determine if our given magic methods can be responded to.
+ *
+ * @param string $method Method name.
+ * @param bool $internal Interal call or not.
+ * @return bool
+ */
+ public function respondsTo($method, $internal = false) {
+ return is_callable(array($this, $method), true);
+ }
+
/**
* Generates a form field with a label, input, and error message (if applicable), all contained
* within a wrapping element.
View
@@ -297,6 +297,17 @@ public function __call($method, $params) {
return $this->applyHandler(null, null, $method, $this->_context[$method]);
}
+ /**
+ * Custom check to determine if our given magic methods can be responded to.
+ *
+ * @param string $method Method name.
+ * @param bool $internal Interal call or not.
+ * @return bool
+ */
+ public function respondsTo($method, $internal = false) {
+ return is_callable(array($this, $method), true);
+ }
+
/**
* Brokers access to helpers attached to this rendering context, and loads helpers on-demand if
* they are not available.
View
@@ -116,6 +116,18 @@ public function __call($comparison, $args) {
return $this;
}
+ /**
+ * Custom check to determine if our given magic methods can be responded to.
+ *
+ * @param string $method Method name.
+ * @param bool $internal Interal call or not.
+ * @return bool
+ */
+ public function respondsTo($method, $internal = false) {
+ $methodExists = in_array($method, array('gt', 'gte', 'lt', 'lte', 'eq'), true);
+ return $methodExists || parent::respondsTo($method, $internal);
+ }
+
/**
* Valides the method was called after the last call.
*
Oops, something went wrong.

0 comments on commit d17172b

Please sign in to comment.