Skip to content

Commit

Permalink
Merge pull request #652 from jails/pr44
Browse files Browse the repository at this point in the history
Refactoring lazy initialization for model metadata
  • Loading branch information
nateabele committed Sep 21, 2012
2 parents f4c5bd2 + 26d2307 commit f2b556e
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 25 deletions.
48 changes: 23 additions & 25 deletions data/Model.php
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -309,7 +309,14 @@ class Model extends \lithium\core\StaticObject {
* @see lithium\data\Model::config() * @see lithium\data\Model::config()
* @var array * @var array
*/ */
protected static $_autoConfig = array('meta', 'finders', 'query', 'schema', 'classes'); protected static $_autoConfig = array(
'meta',
'finders',
'query',
'schema',
'classes',
'initializers'
);


/** /**
* Configures the model for use. This method will set the `Model::$_schema`, `Model::$_meta`, * Configures the model for use. This method will set the `Model::$_schema`, `Model::$_meta`,
Expand Down Expand Up @@ -367,6 +374,7 @@ protected static function _init($class) {
$schema = array(); $schema = array();
$source = array(); $source = array();
$classes = static::$_classes; $classes = static::$_classes;
$initializers = array();


foreach (static::_parents() as $parent) { foreach (static::_parents() as $parent) {
$parentConfig = get_class_vars($parent); $parentConfig = get_class_vars($parent);
Expand All @@ -390,26 +398,25 @@ protected static function _init($class) {
$source = (($conn) ? $conn->configureClass($class) : array()) + $source; $source = (($conn) ? $conn->configureClass($class) : array()) + $source;
} }
static::$_classes = $classes; static::$_classes = $classes;
$name = static::_name();


$local = compact('class', 'name') + $self->_meta; $local = compact('class') + $self->_meta;
$self->_meta = ($local + $source['meta'] + $meta); $self->_meta = ($local + $source['meta'] + $meta);
$meta =& $self->_meta; $meta =& $self->_meta;


if (is_object($schema)) { if (is_object($schema)) {
$schema = $schema->fields(); $schema = $schema->fields();
} }
$self->_initializers += array( $self->_initializers += array(
'source' => function() use (&$meta) { 'name' => function($self) {
return Inflector::tableize($meta['name']); return basename(str_replace('\\', '/', $self));
},
'source' => function($self) {
return Inflector::tableize($self::meta('name'));
}, },
'title' => function() use (&$meta) { 'title' => function($self) {
$titleKeys = array('title', 'name'); $titleKeys = array('title', 'name');

$titleKeys = array_merge($titleKeys, (array) $self::meta('key'));
if (isset($meta['key'])) { return $self::hasField($titleKeys);
$titleKeys = array_merge($titleKeys, (array) $meta['key']);
}
return $meta['class']::hasField($titleKeys);
} }
); );


Expand Down Expand Up @@ -594,14 +601,15 @@ protected function _getMetaKey($key = null) {
if (!$key) { if (!$key) {
$all = array_keys($this->_initializers); $all = array_keys($this->_initializers);
$call = array(&$this, '_getMetaKey'); $call = array(&$this, '_getMetaKey');
return array_combine($all, array_map($call, $all)) + $this->_meta; return $all ? array_combine($all, array_map($call, $all)) + $this->_meta : $this->_meta;
} }


if (isset($this->_meta[$key])) { if (isset($this->_meta[$key])) {
return $this->_meta[$key]; return $this->_meta[$key];
} }
if (isset($this->_initializers[$key]) && $initializer = $this->_initializers[$key]) { if (isset($this->_initializers[$key]) && $initializer = $this->_initializers[$key]) {
return ($this->_meta[$key] = $initializer($this->_meta, $this->_schema)); unset($this->_initializers[$key]);
return ($this->_meta[$key] = $initializer(get_called_class()));
} }
} }


Expand Down Expand Up @@ -753,10 +761,10 @@ public static function bind($type, $name, array $config = array()) {
*/ */
public static function schema($field = null) { public static function schema($field = null) {
$self = static::_object(); $self = static::_object();
$source = $self::meta('source');


if (!is_object($self->_schema)) { if (!is_object($self->_schema)) {
$self->_schema = static::connection()->describe($source, $self->_schema, $self->_meta); $source = $self::meta('source');
$self->_schema = static::connection()->describe($source, $self->_schema, static::meta());


if (!is_object($self->_schema)) { if (!is_object($self->_schema)) {
$class = get_called_class(); $class = get_called_class();
Expand Down Expand Up @@ -1137,16 +1145,6 @@ public static function &connection() {
throw new ConfigException("The data connection `{$name}` is not configured."); throw new ConfigException("The data connection `{$name}` is not configured.");
} }


/**
* Gets just the class name portion of a fully-name-spaced class name, i.e.
* `app\models\Posts::_name()` returns `'Posts'`.
*
* @return string
*/
protected static function _name() {
return basename(str_replace('\\', '/', get_called_class()));
}

/** /**
* Wraps `StaticObject::applyFilter()` to account for object instances. * Wraps `StaticObject::applyFilter()` to account for object instances.
* *
Expand Down
71 changes: 71 additions & 0 deletions tests/cases/data/ModelTest.php
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
namespace lithium\tests\cases\data; namespace lithium\tests\cases\data;


use stdClass; use stdClass;
use lithium\util\Inflector;
use lithium\data\Model; use lithium\data\Model;
use lithium\data\Entity; use lithium\data\Entity;
use lithium\data\Schema; use lithium\data\Schema;
Expand Down Expand Up @@ -801,6 +802,76 @@ public function testLazyLoad() {
$this->expectException($exception); $this->expectException($exception);
MockPost::relations('Unexisting'); MockPost::relations('Unexisting');
} }

public function testLazyMetadataInit() {
MockPost::config(array(
'schema' => new Schema(array(
'fields' => array(
'id' => array('type' => 'integer'),
'name' => array('type' => 'string'),
'label' => array('type' => 'string')
)
))
));

$this->assertIdentical('mock_posts', MockPost::meta('source'));
$this->assertIdentical('name', MockPost::meta('title'));
$this->assertIdentical(null, MockPost::meta('unexisting'));

$config = array(
'schema' => new Schema(array(
'fields' => array(
'id' => array('type' => 'integer'),
'name' => array('type' => 'string'),
'label' => array('type' => 'string')
)
)
),
'initializers' => array(
'source' => function($self) {
return Inflector::tableize($self::meta('name'));
},
'name' => function($self) {
return Inflector::singularize('CoolPosts');
},
'title' => function($self) {
static $i = 1;
return 'label' . $i++;
}
)
);
MockPost::reset();
MockPost::config($config);
$this->assertIdentical('cool_posts', MockPost::meta('source'));
$this->assertIdentical('label1', MockPost::meta('title'));
$this->assertFalse('label2' == MockPost::meta('title'));
$this->assertIdentical('label1', MockPost::meta('title'));
$meta = MockPost::meta();
$this->assertIdentical('label1', $meta['title']);
$this->assertIdentical('CoolPost', MockPost::meta('name'));

MockPost::reset();
unset($config['initializers']['title']);
$config['initializers']['source'] = function($self) {
return Inflector::underscore($self::meta('name'));
};
MockPost::config($config);
$this->assertIdentical('cool_post', MockPost::meta('source'));
$this->assertIdentical('name', MockPost::meta('title'));
$this->assertIdentical('CoolPost', MockPost::meta('name'));

MockPost::reset();
MockPost::config($config);
$expected = array (
'class' => 'lithium\\tests\\mocks\\data\\MockPost',
'connection' => false,
'key' => 'id',
'name' => 'CoolPost',
'title' => 'name',
'source' => 'cool_post'
);
$this->assertEqual($expected, MockPost::meta());
}
} }


?> ?>

0 comments on commit f2b556e

Please sign in to comment.