/test/Mocker.php
PHP | 843 lines | 429 code | 39 blank | 375 comment | 21 complexity | cc73248a2f1c1b7892bdaee248420abc MD5 | raw file
- <?php
- /**
- * li₃: the most RAD framework for PHP (http://li3.me)
- *
- * Copyright 2012, Union of RAD. All rights reserved. This source
- * code is distributed under the terms of the BSD 3-Clause License.
- * The full license text can be found in the LICENSE.txt file.
- */
- namespace lithium\test;
- use lithium\aop\Filters;
- use lithium\util\Text;
- use ReflectionClass;
- use ReflectionMethod;
- use ReflectionFunction;
- use ReflectionFunctionAbstract;
- use Reflection;
- $message = 'lithium\test\Mocker has been deprecated, as alternatives ';
- $message .= 'exist (i.e. Mockery) which take the task of maintaining a ';
- $message .= 'mocking framework from us.';
- trigger_error($message, E_USER_DEPRECATED);
- /**
- * The Mocker class aids in the creation of Mocks on the fly, allowing you to
- * use Lithium filters on most methods in a class as close to the test as
- * possible.
- *
- * ## How to use it
- * To create a new Mock, you need to register `Mocker`, then call or instantiate
- * the same class but with '\Mock' appended to the end of the class name.
- *
- * ### Registering Mocker
- * To enable the autoloading of mocks you simply need to make a simple method
- * call.
- * ```
- * use lithium\core\Environment;
- * use lithium\test\Mocker;
- * if (!Environment::is('production')) {
- * Mocker::register();
- * }
- * ```
- *
- * You can also enable autoloading inside the setup of a unit test class. This
- * method can be called redundantly.
- * ```
- * use lithium\test\Mocker;
- * class MockerTest extends \lithium\test\Unit {
- * public function setUp() {
- * Mocker::register();
- * }
- * }
- * ```
- *
- * ### Usage and Examples
- * Using Mocker is the fun magical part, it's autoloaded so simply call the
- * class you want to mock with the '\Mock' at the end. The autoloader will
- * detect you want to autoload it, and create it for you. Now you can filter
- * any method.
- *
- * ```
- * use lithium\console\dispatcher\Mock as DispatcherMock;
- * $dispatcher = new DispatcherMock();
- * $dispatcher->applyFilter('config', function($params, $next) {
- * return [];
- * });
- * $results = $dispatcher->config();
- * ```
- * ```
- * use lithium\analysis\parser\Mock as ParserMock;
- * $code = 'echo "foobar";';
- * ParserMock::applyFilter('config', function($params, $next) {
- * return [];
- * });
- * $tokens = ParserMock::tokenize($code, ['wrap' => true]);
- * ```
- *
- * Mocker also gives the ability, if used correctly, to stub build in php
- * function calls. Consider the following example.
- * ```
- * namespace app\extensions;
- *
- * class AwesomeFileEditor {
- *
- * public static function updateJson($file) {
- * if (file_exists($file)) {
- * $time = microtime(true);
- * $packages = json_decode(file_get_contents($file), true);
- * foreach ($packages['users'] as &$package) {
- * $package['updated'] = $time;
- * }
- * return $packages;
- * }
- * return false;
- * }
- *
- * }
- * ```
- * ```
- * namespace app\tests\cases\extensions;
- *
- * use lithium\test\Mocker;
- * use app\extensions\AwesomeFileEditor;
- *
- * class AwesomeFileEditorTest extends \lithium\test\Unit {
- *
- * public function setUp() {
- * Mocker::overwriteFunction(false);
- * }
- *
- * public function testUpdateJson() {
- * Mocker::overwriteFunction('app\extensions\file_exists', function() {
- * return true;
- * });
- * Mocker::overwriteFunction('app\extensions\file_get_contents', function() {
- * return <<<EOD
- * {
- * "users": [
- * {
- * "name": "BlaineSch",
- * "updated": 0
- * }
- * ]
- * }
- * EOD;
- * });
- *
- * $results = AwesomeFileEditor::updateJson('idontexist.json');
- * $this->assertNotEqual(0, $results['users'][0]['updated']);
- * }
- *
- * }
- * ```
- *
- * ## How does Mocking classes work?
- * This section isn't necessary to read, but can help others better understand
- * it so that they can add new features, or debug current ones.
- *
- * ### TLDR
- * The `Mocker` class dynamically makes two classes, a `Delegate` and a `Mock`.
- * Both of these classes extend the target class. The `Delegate` is passed into
- * the `Mock` class for it to call within (anonymous functions) filters. This
- * allows public and protected methods to be filterable.
- *
- * ### Theory
- * I'll walk you through the steps I did in order to figure out how `Mocker`
- * should work. The goal here is to mock class `Person`.
- *
- * ```
- * class Person {
- * public function speak() {
- * $this->_openMouth();
- * return true;
- * }
- * protected function _openMouth() {
- * return $this->mouth = 'open';
- * }
- * }
- * ```
- *
- * In order to make the `speak()` method filterable we'll need to create a class
- * called `MockPerson` and we'll make its `speak()` method filterable, however
- * there is already an issue since a filter works inside of an anonymous
- * function you cannot call `parent`, so `MockPerson` will also need an instance
- * of `Person`.
- *
- * ```
- * class MockPerson extends Person {
- * public $person;
- * public function speak() {
- * $params = compact();
- * $person = $this->person;
- * return Filters::run($this, __FUNCTION__, [], function($params) use (&$person) {
- * return $person->speak();
- * };
- * }
- * }
- * ```
- *
- * You might stop here and call it a day, but what about filtering protected
- * methods? For example you might want to make sure `_openMouth()` does not
- * modify the class. However this isn't possible with the current implementation
- * since `_openMouth` is protected and we can't call protected methods within an
- * anonymous function. The trick is that when you are extending a class you can
- * make a method MORE visible than its parent, with the exception of private
- * methods. So let's make a class `DelegatePerson` that simply extends `Person`
- * and makes `_openMouth()` public.
- *
- * ```
- * class DelegatePerson extends Person {
- * public function _openMouth() {
- * parent::_openMouth();
- * }
- * }
- * ```
- *
- * Now we simply pass `DelegatePerson` to `MockPerson` and all methods are now
- * filterable.
- *
- * ## How does overwriting PHP functions work?
- * In short, this is a hack. When you are inside of a namespace `foo\bar\baz`
- * and you call a function `file_get_contents` it first searches the current
- * namespace for that function `foo\bar\baz\file_get_contents`. `Mocker` simply
- * creates that function dynamically, so when its called it delegates back to
- * `Mocker` which will determine if it should call a user-defined function or
- * if it should go back to the original PHP function.
- *
- * @deprecated Please use an alternative mocking framework, i.e. Mockery.
- */
- class Mocker {
- /**
- * Functions to be called instead of the original.
- *
- * The key is the fully namespaced function name, and the value is the closure to be called.
- *
- * @var array
- */
- protected static $_functionCallbacks = [];
- /**
- * Results of function calls for later assertion in `MockerChain`.
- *
- * @var array
- */
- protected static $_functionResults = [];
- /**
- * A list of code to be generated for the `Delegate`.
- *
- * The `Delegate` directly extends the class you wish to mock and makes all
- * methods publically available to other classes but should not be accessed
- * directly by any other classes other than `Mock`.
- *
- * @item variable `$parent` Instance of `Mock`. Allows `Delegate` to send
- * calls back to `Mock` if it was called directly
- * from a parent class.
- * @var array
- */
- protected static $_mockDelegateIngredients = [
- 'startClass' => [
- 'namespace {:namespace};',
- 'class MockDelegate extends \{:mocker} {',
- ' public $parent = null;',
- ],
- 'constructor' => [
- '{:modifiers} function __construct({:args}) {',
- ' $args = compact({:stringArgs});',
- ' $argCount = func_num_args();',
- ' $this->parent = $argCount === 0 ? false : func_get_arg($argCount - 1);',
- ' if (!is_a($this->parent, __NAMESPACE__ . "\Mock")) {',
- ' $class = new \ReflectionClass(\'{:namespace}\Mock\');',
- ' $this->parent = $class->newInstanceArgs($args);',
- ' }',
- ' $this->parent->mocker = $this;',
- ' if (method_exists(\'{:mocker}\', "__construct")) {',
- ' call_user_func_array("parent::__construct", $args);',
- ' }',
- '}',
- ],
- 'method' => [
- '{:modifiers} function {:method}({:args}) {',
- ' $args = compact({:stringArgs});',
- ' $token = spl_object_hash($this);',
- ' if (func_num_args() > 0 && func_get_arg(func_num_args() - 1) === $token) {',
- ' return call_user_func_array("parent::{:method}", compact({:stringArgs}));',
- ' }',
- ' $method = [$this->parent, "{:method}"];',
- ' return call_user_func_array($method, $args);',
- '}',
- ],
- 'staticMethod' => [
- '{:modifiers} function {:method}({:args}) {',
- ' $args = compact({:stringArgs});',
- ' $token = "1f3870be274f6c49b3e31a0c6728957f";',
- ' if (func_num_args() > 0 && func_get_arg(func_num_args() - 1) === $token) {',
- ' return call_user_func_array("parent::{:method}", compact({:stringArgs}));',
- ' }',
- ' $method = \'{:namespace}\Mock::{:method}\';',
- ' return call_user_func_array($method, $args);',
- '}',
- ],
- 'endClass' => [
- '}',
- ],
- ];
- /**
- * List of code to be generated for overwriting php functions.
- *
- * @var array
- */
- protected static $_mockFunctionIngredients = [
- 'function' => [
- 'namespace {:namespace};',
- 'use lithium\test\Mocker;',
- 'function {:function}({:args}) {',
- ' $params = [];',
- ' foreach ([{:stringArgs}] as $value) {',
- ' if (!empty($value)) {',
- ' $params[] =& ${$value};',
- ' }',
- ' }',
- ' return Mocker::callFunction(__FUNCTION__, $params);',
- '}',
- ],
- ];
- /**
- * A list of code to be generated for the `Mock`.
- *
- * The Mock class directly extends the class you wish to mock but only
- * interacts with the `Delegate` directly. This class is the public
- * interface for users.
- *
- * @item variable `$results` All method calls allowing you for you make your
- * own custom assertions.
- * @item variable `$staticResults` See `$results`.
- * @item variable `$mocker` Home of the `Delegate` defined above.
- * @item variable `$_safeVars` Variables that should not be deleted on
- * `Mock`. We delete them so they cannot be
- * accessed directly, but sent to `Delegate` via
- * PHP magic methods on `Mock`.
- * @var array
- */
- protected static $_mockIngredients = [
- 'startClass' => [
- 'namespace {:namespace};',
- 'use lithium\aop\Filters as _Filters;',
- 'class Mock extends \{:mocker} {',
- ' public $mocker;',
- ' public $results = [];',
- ' public static $staticResults = [];',
- ' protected $_safeVars = [',
- ' "_classes",',
- ' "mocker",',
- ' "_safeVars",',
- ' "results",',
- ' "staticResults",',
- ' "_methodFilters",',
- ' ];',
- ],
- 'get' => [
- 'public function {:reference}__get($name) {',
- ' $data ={:reference} $this->mocker->$name;',
- ' return $data;',
- '}',
- ],
- 'set' => [
- 'public function __set($name, $value = null) {',
- ' return $this->mocker->$name = $value;',
- '}',
- ],
- 'isset' => [
- 'public function __isset($name) {',
- ' return isset($this->mocker->$name);',
- '}',
- ],
- 'unset' => [
- 'public function __unset($name) {',
- ' unset($this->mocker->$name);',
- '}',
- ],
- 'constructor' => [
- '{:modifiers} function __construct({:args}) {',
- ' $args = compact({:stringArgs});',
- ' array_push($args, $this);',
- ' foreach (get_class_vars(get_class($this)) as $key => $value) {',
- ' if (isset($this->{$key}) && !in_array($key, $this->_safeVars)) {',
- ' unset($this->$key);',
- ' }',
- ' }',
- ' $class = new \ReflectionClass(\'{:namespace}\MockDelegate\');',
- ' $class->newInstanceArgs($args);',
- '}',
- ],
- 'destructor' => [
- 'public function __destruct() {}',
- ],
- 'staticMethod' => [
- '{:modifiers} function {:method}({:args}) {',
- ' $args = compact({:stringArgs});',
- ' $args["hash"] = "1f3870be274f6c49b3e31a0c6728957f";',
- ' $method = \'{:namespace}\MockDelegate::{:method}\';',
- ' $result = _Filters::run(__CLASS__, "{:method}", $args,',
- ' function($args) use(&$method) {',
- ' return call_user_func_array($method, $args);',
- ' }',
- ' );',
- ' if (!isset(static::$staticResults["{:method}"])) {',
- ' static::$staticResults["{:method}"] = [];',
- ' }',
- ' static::$staticResults["{:method}"][] = [',
- ' "args" => func_get_args(),',
- ' "result" => $result,',
- ' "time" => microtime(true),',
- ' ];',
- ' return $result;',
- '}',
- ],
- 'method' => [
- '{:modifiers} function {:method}({:args}) {',
- ' $args = compact({:stringArgs});',
- ' $args["hash"] = spl_object_hash($this->mocker);',
- ' $_method = [$this->mocker, "{:method}"];',
- ' $result = _Filters::run(__CLASS__, "{:method}", $args,',
- ' function($args) use(&$_method) {',
- ' return call_user_func_array($_method, $args);',
- ' }',
- ' );',
- ' if (!isset($this->results["{:method}"])) {',
- ' $this->results["{:method}"] = [];',
- ' }',
- ' $this->results["{:method}"][] = [',
- ' "args" => func_get_args(),',
- ' "result" => $result,',
- ' "time" => microtime(true),',
- ' ];',
- ' return $result;',
- '}',
- ],
- 'applyFilter' => [
- 'public {:static} function applyFilter($method, $filter = null) {',
- ' $message = "<mocked class>::applyFilter() is deprecated. ";',
- ' $message .= "Use Filters::applyFilter(" . __CLASS__ .", ...) instead.";',
- ' // trigger_error($message, E_USER_DEPRECATED);',
- ' foreach ((array) $method as $m) {',
- ' if ($filter === null) {',
- ' _Filters::clear(__CLASS__, $m);',
- ' } else {',
- ' _Filters::apply(__CLASS__, $m, $filter);',
- ' }',
- ' }',
- '}',
- ],
- 'endClass' => [
- '}',
- ],
- ];
- /**
- * A list of methods we should not overwrite in our mock class.
- *
- * Some of these methods are are too custom inside the `Mock` or `Delegate`,
- * while others should simply not be filtered.
- *
- * @var array
- */
- protected static $_blackList = [
- '__destruct', '_parents',
- '__get', '__set', '__isset', '__unset', '__sleep',
- '__wakeup', '__toString', '__clone', '__invoke',
- '_stop', '_init', 'invokeMethod', '__set_state',
- '_instance', '_object', '_initialize',
- '_filter', 'applyFilter',
- ];
- /**
- * Will register this class into the autoloader.
- *
- * @return void
- */
- public static function register() {
- spl_autoload_register([__CLASS__, 'create']);
- }
- /**
- * The main entrance to create a new Mock class.
- *
- * @param string $mockee The fully namespaced `\Mock` class
- * @return void
- */
- public static function create($mockee) {
- if (!static::_validateMockee($mockee)) {
- return;
- }
- $mocker = static::_mocker($mockee);
- $isStatic = is_subclass_of($mocker, 'lithium\core\StaticObjectDeprecated');
- $tokens = [
- 'namespace' => static::_namespace($mockee),
- 'mocker' => $mocker,
- 'mockee' => 'MockDelegate',
- 'static' => $isStatic ? 'static' : '',
- ];
- $mockDelegate = static::_dynamicCode('mockDelegate', 'startClass', $tokens);
- $mock = static::_dynamicCode('mock', 'startClass', $tokens);
- $reflectedClass = new ReflectionClass($mocker);
- $reflecedMethods = $reflectedClass->getMethods();
- $getByReference = false;
- $staticApplyFilter = true;
- $constructor = false;
- foreach ($reflecedMethods as $methodId => $method) {
- if (!in_array($method->name, static::$_blackList)) {
- $key = $method->isStatic() ? 'staticMethod' : 'method';
- if ($method->name === '__construct') {
- $key = 'constructor';
- $constructor = true;
- }
- $docs = ReflectionMethod::export($mocker, $method->name, true);
- if (preg_match('/&' . $method->name . '/', $docs) === 1) {
- continue;
- }
- $tokens = [
- 'namespace' => static::_namespace($mockee),
- 'method' => $method->name,
- 'modifiers' => static::_methodModifiers($method),
- 'args' => static::_methodParams($method),
- 'stringArgs' => static::_stringMethodParams($method),
- 'mocker' => $mocker,
- ];
- $mockDelegate .= static::_dynamicCode('mockDelegate', $key, $tokens);
- $mock .= static::_dynamicCode('mock', $key, $tokens);
- } elseif ($method->name === '__get') {
- $docs = ReflectionMethod::export($mocker, '__get', true);
- $getByReference = preg_match('/&__get/', $docs) === 1;
- } elseif ($method->name === 'applyFilter') {
- $staticApplyFilter = $method->isStatic();
- }
- }
- if (!$constructor) {
- $tokens = [
- 'namespace' => static::_namespace($mockee),
- 'modifiers' => 'public',
- 'args' => null,
- 'stringArgs' => 'array()',
- 'mocker' => $mocker,
- ];
- $mock .= static::_dynamicCode('mock', 'constructor', $tokens);
- $mockDelegate .= static::_dynamicCode('mockDelegate', 'constructor', $tokens);
- }
- $mockDelegate .= static::_dynamicCode('mockDelegate', 'endClass');
- $mock .= static::_dynamicCode('mock', 'get', [
- 'reference' => $getByReference ? '&' : '',
- ]);
- $mock .= static::_dynamicCode('mock', 'set');
- $mock .= static::_dynamicCode('mock', 'isset');
- $mock .= static::_dynamicCode('mock', 'unset');
- $mock .= static::_dynamicCode('mock', 'applyFilter', [
- 'static' => $staticApplyFilter ? 'static' : '',
- ]);
- $mock .= static::_dynamicCode('mock', 'destructor');
- $mock .= static::_dynamicCode('mock', 'endClass');
- eval($mockDelegate . $mock);
- }
- /**
- * Will determine what method mofifiers of a method.
- *
- * For instance: 'public static' or 'private abstract'
- *
- * @param ReflectionMethod $method
- * @return string
- */
- protected static function _methodModifiers(ReflectionMethod $method) {
- $modifierKey = $method->getModifiers();
- $modifierArray = Reflection::getModifierNames($modifierKey);
- $modifiers = implode(' ', $modifierArray);
- return str_replace(['private', 'protected'], 'public', $modifiers);
- }
- /**
- * Will determine what parameter prototype of a method.
- *
- * For instance: 'ReflectionFunctionAbstract $method' or '$name, array $foo = null'
- *
- * @param ReflectionFunctionAbstract $method
- * @return string
- */
- protected static function _methodParams(ReflectionFunctionAbstract $method) {
- $pattern = '/Parameter #[0-9]+ \[ [^\>]+>([^\]]+) \]/';
- $replace = [
- 'from' => [' Array', 'or NULL'],
- 'to' => [' array()', ''],
- ];
- preg_match_all($pattern, $method, $matches);
- $params = implode(', ', $matches[1]);
- return str_replace($replace['from'], $replace['to'], $params);
- }
- /**
- * Will return the params in a way that can be placed into `compact()`
- *
- * @param ReflectionFunctionAbstract $method
- * @return string
- */
- protected static function _stringMethodParams(ReflectionFunctionAbstract $method) {
- $pattern = '/Parameter [^$]+\$([^ ]+)/';
- preg_match_all($pattern, $method, $matches);
- $params = implode("', '", $matches[1]);
- return strlen($params) > 0 ? "'{$params}'" : 'array()';
- }
- /**
- * Will generate the code you are wanting.
- *
- * This pulls from $_mockDelegateIngredients and $_mockIngredients.
- *
- * @param string $type The name of the array of ingredients to use
- * @param string $key The key from the array of ingredients
- * @param array $tokens Tokens, if any, that should be inserted
- * @return string
- */
- protected static function _dynamicCode($type, $key, $tokens = []) {
- $defaults = [
- 'master' => '\lithium\test\Mocker',
- ];
- $tokens += $defaults;
- $name = '_' . $type . 'Ingredients';
- $code = implode("\n", static::${$name}[$key]);
- return Text::insert($code, $tokens) . "\n";
- }
- /**
- * Will generate the mocker from the current mockee.
- *
- * @param string $mockee The fully namespaced `\Mock` class
- * @return array
- */
- protected static function _mocker($mockee) {
- $sections = explode('\\', $mockee);
- array_pop($sections);
- $sections[] = ucfirst(array_pop($sections));
- return implode('\\', $sections);
- }
- /**
- * Will generate the namespace from the current mockee.
- *
- * @param string $mockee The fully namespaced `\Mock` class
- * @return string
- */
- protected static function _namespace($mockee) {
- $matches = [];
- preg_match_all('/^(.*)\\\\Mock$/', $mockee, $matches);
- return isset($matches[1][0]) ? $matches[1][0] : null;
- }
- /**
- * Will validate if mockee is a valid class we should mock.
- *
- * Will fail if the mock already exists, or it doesn't contain `\Mock` in
- * the namespace.
- *
- * @param string $mockee The fully namespaced `\Mock` class
- * @return bool
- */
- protected static function _validateMockee($mockee) {
- return preg_match('/\\\\Mock$/', $mockee) === 1;
- }
- /**
- * Generate a chain class with the current rules of the mock.
- *
- * @param mixed $mock Mock object, namespaced static mock, namespaced function name.
- * @return object MockerChain instance
- */
- public static function chain($mock) {
- $results = [];
- $string = is_string($mock);
- if (is_object($mock) && isset($mock->results)) {
- $results = static::mergeResults($mock->results, $mock::$staticResults);
- } elseif ($string && class_exists($mock) && isset($mock::$staticResults)) {
- $results = $mock::$staticResults;
- } elseif ($string && function_exists($mock) && isset(static::$_functionResults[$mock])) {
- $results = [$mock => static::$_functionResults[$mock]];
- }
- return new MockerChain($results);
- }
- /**
- * Will merge two sets of results into each other.
- *
- * @param array $results
- * @param array $secondary
- * @return array
- */
- public static function mergeResults($results, $secondary) {
- foreach ($results as $method => $calls) {
- if (isset($secondary[$method])) {
- $results['method1'] = array_merge($results['method1'], $secondary['method1']);
- usort($results['method1'], function($el1, $el2) {
- return strcmp($el1['time'], $el2['time']);
- });
- unset($secondary['method1']);
- }
- }
- return $results + $secondary;
- }
- /**
- * Calls a method on this object with the given parameters. Provides an OO wrapper for
- * `forward_static_call_array()`.
- *
- * @param string $method Name of the method to call.
- * @param array $params Parameter list to use when calling `$method`.
- * @return mixed Returns the result of the method call.
- */
- public static function invokeMethod($method, $params = []) {
- return forward_static_call_array([get_called_class(), $method], $params);
- }
- /**
- * Will overwrite namespaced functions.
- *
- * @param string|bool $name Fully namespaced function, or `false` to reset functions.
- * @param closure|bool $callback Callback to be called, or `false` to reset this function.
- * @return void
- */
- public static function overwriteFunction($name, $callback = null) {
- if ($name === false) {
- static::$_functionResults = [];
- return static::$_functionCallbacks = [];
- }
- if ($callback === false) {
- static::$_functionResults[$name] = [];
- return static::$_functionCallbacks[$name] = false;
- }
- static::$_functionCallbacks[$name] = $callback;
- if (function_exists($name)) {
- return;
- }
- $function = new ReflectionFunction($callback);
- $pos = strrpos($name, '\\');
- eval(static::_dynamicCode('mockFunction', 'function', [
- 'namespace' => substr($name, 0, $pos),
- 'function' => substr($name, $pos + 1),
- 'args' => static::_methodParams($function),
- 'stringArgs' => static::_stringMethodParams($function),
- ]));
- return;
- }
- /**
- * A method to call user defined functions.
- *
- * This method should only be accessed by functions created by `Mocker::overwriteFunction()`.
- *
- * If no matching stored function exists, the global function will be called instead.
- *
- * @param string $name Fully namespaced function name to call.
- * @param array $params Params to be passed to the function.
- * @return mixed
- */
- public static function callFunction($name, array &$params = []) {
- $function = substr($name, strrpos($name, '\\'));
- $exists = isset(static::$_functionCallbacks[$name]);
- if ($exists && is_callable(static::$_functionCallbacks[$name])) {
- $function = static::$_functionCallbacks[$name];
- }
- $result = call_user_func_array($function, $params);
- if (!isset(static::$_functionResults[$name])) {
- static::$_functionResults[$name] = [];
- }
- static::$_functionResults[$name][] = [
- 'args' => $params,
- 'result' => $result,
- 'time' => microtime(true),
- ];
- return $result;
- }
- /* Deprecated / BC */
- /**
- * Stores the closures that represent the method filters. They are indexed by called class.
- *
- * @deprecated
- * @var array Method filters, indexed by class.
- */
- protected static $_methodFilters = [];
- /**
- * Apply a closure to a method of the current static object.
- *
- * @deprecated
- * @see lithium\core\StaticObject::_filter()
- * @see lithium\util\collection\Filters
- * @param string $class Fully namespaced class to apply filters.
- * @param mixed $method The name of the method to apply the closure to. Can either be a single
- * method name as a string, or an array of method names. Can also be false to remove
- * all filters on the current object.
- * @param \Closure $filter The closure that is used to filter the method(s), can also be false
- * to remove all the current filters for the given method.
- * @return void
- */
- public static function applyFilter($class, $method = null, $filter = null) {
- $message = '`' . __METHOD__ . '()` has been deprecated in favor of ';
- $message .= '`\lithium\aop\Filters::apply()` and `::clear()`.';
- trigger_error($message, E_USER_DEPRECATED);
- $class = get_called_class();
- if ($method === false) {
- Filters::clear($class);
- return;
- }
- foreach ((array) $method as $m) {
- if ($filter === false) {
- Filters::clear($class, $m);
- } else {
- Filters::apply($class, $m, $filter);
- }
- }
- }
- /**
- * Executes a set of filters against a method by taking a method's main implementation as a
- * callback, and iteratively wrapping the filters around it.
- *
- * @deprecated
- * @see lithium\util\collection\Filters
- * @param string $class Fully namespaced class to apply filters.
- * @param string|array $method The name of the method being executed, or an array containing
- * the name of the class that defined the method, and the method name.
- * @param array $params An associative array containing all the parameters passed into
- * the method.
- * @param \Closure $callback The method's implementation, wrapped in a closure.
- * @param array $filters Additional filters to apply to the method for this call only.
- * @return mixed
- */
- protected static function _filter($class, $method, $params, $callback, $filters = []) {
- $message = '`' . __METHOD__ . '()` has been deprecated in favor of ';
- $message .= '`\lithium\aop\Filters::run()` and `::apply()`.';
- trigger_error($message, E_USER_DEPRECATED);
- $class = get_called_class();
- foreach ($filters as $filter) {
- Filters::apply($class, $method, $filter);
- }
- return Filters::run($class, $method, $params, $callback);
- }
- }
- ?>