Skip to content

Commit

Permalink
Making \core\Libraries::instance() filterable, and refactoring `\co…
Browse files Browse the repository at this point in the history
…re\Object::_instance()` and `\core\StaticObject::_instance()` to depend on it. Updating affected test cases and console commands.
  • Loading branch information
nateabele committed Mar 12, 2011
1 parent a6ba843 commit a12db0c
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 33 deletions.
9 changes: 7 additions & 2 deletions libraries/lithium/console/command/Create.php
Expand Up @@ -8,9 +8,10 @@

namespace lithium\console\command;

use lithium\util\String;
use lithium\core\Libraries;
use lithium\util\Inflector;
use lithium\util\String;
use lithium\core\ClassNotFoundException;

/**
* The `create` command allows you to rapidly develop your models, views, controllers, and tests
Expand Down Expand Up @@ -112,7 +113,11 @@ public function interactive() {
* @return void
*/
protected function _execute($command) {
if (!$class = $this->_instance($command)) {
try {
if (!$class = $this->_instance($command)) {
return false;
}
} catch (ClassNotFoundException $e) {
return false;
}
$data = array();
Expand Down
9 changes: 8 additions & 1 deletion libraries/lithium/console/command/create/Test.php
Expand Up @@ -11,6 +11,7 @@
use lithium\core\Libraries;
use lithium\util\Inflector;
use lithium\analysis\Inspector;
use lithium\core\ClassNotFoundException;

/**
* Generate a Test class in the `--library` namespace
Expand Down Expand Up @@ -86,7 +87,13 @@ protected function _name($request) {
$type = $request->action;
$name = $request->args();

if ($command = $this->_instance($type)) {
try {
$command = $this->_instance($type);
} catch (ClassNotFoundException $e) {
$command = null;
}

if ($command) {
$request->params['action'] = $name;
$name = $command->invokeMethod('_class', array($request));
}
Expand Down
64 changes: 58 additions & 6 deletions libraries/lithium/core/Libraries.php
Expand Up @@ -56,6 +56,13 @@
*/
class Libraries {

/**
* Stores the closures that represent the method filters. They are indexed by method name.
*
* @var array
*/
protected static $_methodFilters = array();

/**
* The list of class libraries registered with the class loader.
*
Expand Down Expand Up @@ -572,12 +579,54 @@ protected static function _transformPath($transform, $class, array $options = ar
* @return object If the class is found, returns an instance of it, otherwise throws an
* exception.
* @throws lithium\core\ClassNotFoundException Throws an exception if the class can't be found.
* @filter
*/
public static function instance($type, $name, array $options = array()) {
if (!$class = (string) static::locate($type, $name)) {
throw new ClassNotFoundException("Class `{$name}` of type `{$type}` not found.");
$params = compact('type', 'name', 'options');
$_paths =& static::$_paths;

$implementation = function($self, $params) use (&$_paths) {
$name = $params['name'];
$type = $params['type'];

if (!$name && !$type) {
$message = "Invalid class lookup: `\$name` and `\$type` are empty.";
throw new ClassNotFoundException($message);
}
if (!is_string($type) && $type !== null && !isset($_paths[$type])) {
throw new ClassNotFoundException("Invalid class type `{$type}`.");
}
if (!$class = $self::locate($type, $name)) {
throw new ClassNotFoundException("Class `{$name}` of type `{$type}` not found.");
}
if (is_object($class)) {
return $class;
}
$success = (is_string($class) && class_exists($class));
return $success ? new $class($params['options']) : null;
};
if (!isset(static::$_methodFilters[__FUNCTION__])) {
return $implementation(get_called_class(), $params);
}
return class_exists($class) ? new $class($options) : null;
$class = get_called_class();
$method = __FUNCTION__;
$data = array_merge(static::$_methodFilters[__FUNCTION__], array($implementation));
return Filters::run($class, $params, compact('data', 'class', 'method'));
}

/**
* Apply a closure to a method in `Libraries`.
*
* @see lithium\util\collection\Filters
* @param string $method The name of the method to apply the closure to.
* @param closure $filter The closure that is used to filter the method.
* @return void
*/
public static function applyFilter($method, $filter = null) {
if (!isset(static::$_methodFilters[$method])) {
static::$_methodFilters[$method] = array();
}
static::$_methodFilters[$method][] = $filter;
}

/**
Expand Down Expand Up @@ -766,10 +815,13 @@ protected static function _searchPaths($paths, $library, $params) {
* @return array
*/
protected static function _locateAll(array $params, array $options = array()) {
$defaults = array(
'libraries' => null, 'recursive' => true, 'namespaces' => false
);
$defaults = array('libraries' => null, 'recursive' => true, 'namespaces' => false);
$options += $defaults;

if (!isset(static::$_paths[$params['type']])) {
var_dump($params['type']);
die();
}
$paths = (array) static::$_paths[$params['type']];
$libraries = $options['library'] ? $options['library'] : $options['libraries'];
$libraries = static::get((array) $libraries);
Expand Down
16 changes: 6 additions & 10 deletions libraries/lithium/core/Object.php
Expand Up @@ -8,6 +8,7 @@

namespace lithium\core;

use lithium\core\Libraries;
use lithium\util\collection\Filters;

/**
Expand Down Expand Up @@ -205,19 +206,14 @@ public static function __set_state($data) {
* in `_init` to create the dependencies used in the current class.
*
* @param string|object $name A `classes` key or fully-namespaced class name.
* @param array $config The configuration passed to the constructor.
* @return void
* @param array $options The configuration passed to the constructor.
* @return object
*/
protected function _instance($name, array $config = array()) {
if (is_object($name) || !$name) {
return $name;
}
$name = (string) $name;

if (isset($this->_classes[$name])) {
protected function _instance($name, array $options = array()) {
if (is_string($name) && isset($this->_classes[$name])) {
$name = $this->_classes[$name];
}
return (is_string($name) && class_exists($name)) ? new $name($config) : null;
return Libraries::instance(null, $name, $options);
}

/**
Expand Down
14 changes: 6 additions & 8 deletions libraries/lithium/core/StaticObject.php
Expand Up @@ -8,6 +8,7 @@

namespace lithium\core;

use lithium\core\Libraries;
use lithium\util\collection\Filters;

/**
Expand Down Expand Up @@ -87,17 +88,14 @@ public static function invokeMethod($method, $params = array()) {
* in `_init` to create the dependencies used in the current class.
*
* @param string|object $name A `classes` key or fully-namespaced class name.
* @param array $config The configuration passed to the constructor.
* @return void
* @param array $options The configuration passed to the constructor.
* @return object
*/
protected static function _instance($name, array $config = array()) {
if (is_object($name) || !$name) {
return $name;
}
if (isset(static::$_classes[$name])) {
protected static function _instance($name, array $options = array()) {
if (is_string($name) && isset(static::$_classes[$name])) {
$name = static::$_classes[$name];
}
return new $name($config);
return Libraries::instance(null, $name, $options);
}

/**
Expand Down
7 changes: 4 additions & 3 deletions libraries/lithium/tests/cases/core/ObjectTest.php
Expand Up @@ -9,6 +9,7 @@
namespace lithium\tests\cases\core;

use lithium\core\Object;
use lithium\tests\mocks\core\MockRequest;
use lithium\tests\mocks\core\MockMethodFiltering;
use lithium\tests\mocks\core\MockExposed;
use lithium\tests\mocks\core\MockCallable;
Expand Down Expand Up @@ -193,16 +194,16 @@ public function testInstanceWithNamespacedClass() {

public function testInstanceWithObject() {
$object = new MockInstantiator();
$request = new \lithium\tests\mocks\core\MockRequest();
$request = new MockRequest();
$expected = 'lithium\tests\mocks\core\MockRequest';
$result = get_class($object->instance($request));
$this->assertEqual($expected, $result);
}

public function testInstanceFalse() {
$object = new MockInstantiator();
$result = $object->instance(false);
$this->assertFalse($result);
$this->expectException('/^Invalid class lookup/');
$object->instance(false);
}
}

Expand Down
7 changes: 4 additions & 3 deletions libraries/lithium/tests/cases/core/StaticObjectTest.php
Expand Up @@ -9,6 +9,7 @@
namespace lithium\tests\cases\core;

use lithium\core\StaticObject;
use lithium\tests\mocks\core\MockRequest;
use lithium\tests\mocks\core\MockStaticInstantiator;

class StaticObjectTest extends \lithium\test\Unit {
Expand Down Expand Up @@ -151,15 +152,15 @@ public function testInstanceWithNamespacedClass() {
}

public function testInstanceWithObject() {
$request = new \lithium\tests\mocks\core\MockRequest();
$request = new MockRequest();
$expected = 'lithium\tests\mocks\core\MockRequest';
$result = get_class(MockStaticInstantiator::instance($request));
$this->assertEqual($expected, $result);
}

public function testInstanceFalse() {
$result = MockStaticInstantiator::instance(false);
$this->assertFalse($result);
$this->expectException('/^Invalid class lookup/');
MockStaticInstantiator::instance(false);
}
}

Expand Down

0 comments on commit a12db0c

Please sign in to comment.