Skip to content

Commit

Permalink
Rebuild lazy loading so there will be more compatibility with differe…
Browse files Browse the repository at this point in the history
…nt scenarios.
  • Loading branch information
Phally committed Aug 5, 2010
1 parent 7c84530 commit 9367858
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 31 deletions.
73 changes: 42 additions & 31 deletions libs/lazy_model.php
@@ -1,45 +1,31 @@
<?php
abstract class LazyModel extends Model {
public $actsAs = array('Containable');

private $__userAssociations = array();
private $__aliases = array();
private $__joinClasses = array();
private $map = array();

public function __construct($id = false, $table = null, $ds = null) {

foreach ($this->__associations as $type) {
$this->__userAssociations[$type] = $this->{$type};
$this->__aliases = array_merge($this->__aliases, array_keys($this->{$type}));
}

foreach (Set::extract('/with/.', array_values($this->hasAndBelongsToMany)) as $raw) {
list($plugin, $alias) = pluginSplit($raw);
$this->__joinClasses[$alias] = $raw;
foreach ($this->{$type} as $key => $properties) {
$this->map($type, $key, $properties, $id);
}
}

parent::__construct($id, $table, $ds);

}

public function __constructLinkedModel() {
}

public function __isset($alias) {
return $alias && in_array($alias, array_merge($this->__aliases, $this->__joinClasses));
return array_key_exists($alias, $this->map);
}

public function __get($alias) {
foreach ($this->__userAssociations as $type => $associations) {
if (isset($associations[$alias]) || in_array($alias, array_keys($this->__joinClasses))) {
$class = isset($associations[$alias]) ? $associations[$alias]['className'] : $this->__joinClasses[$alias];
$this->__constructLazyLinkedModel($alias, $class);
return $this->{$alias};
}
if (isset($this->map[$alias])) {
$this->constructLazyLinkedModel($alias, $this->map[$alias]);
}
return $this->{$alias};
}

private function __constructLazyLinkedModel($alias, $class = null) {
private function constructLazyLinkedModel($alias, $class = null) {
$this->{$alias} = ClassRegistry::init(compact('class', 'alias'));
if (strpos($class, '.') !== false) {
ClassRegistry::addObject($class, $this->{$alias});
Expand All @@ -49,16 +35,41 @@ private function __constructLazyLinkedModel($alias, $class = null) {

public function bindModel($models, $reset = true) {
foreach ($models as $type => &$data) {
foreach ($data as $alias => &$join) {
if ($type == 'belongsTo' && isset($this->__userAssociations['hasMany'][$alias]['className'])) {
$join['className'] = $this->__userAssociations['hasMany'][$alias]['className'];
}
$this->__userAssociations[$type][$alias] = $join;
$this->__aliases[] = $alias;
foreach ($data as $key => &$properties) {
$this->map($type, $key, $properties);
}
}
parent::bindModel($models, $reset);
}

private function map($type, $key, $properties, $id = null) {
if (is_numeric($key)) {
list($plugin, $alias) = pluginSplit($properties);
$properties = array('className' => $properties);
} else {
$alias = $key;
}

$this->addToMap($alias, $properties['className']);

if ($type == 'hasAndBelongsToMany') {
if (isset($properties['with'])) {
list($plugin, $alias) = pluginSplit($properties['with']);
$this->addToMap($alias, $properties['with']);
} else {
$current = (is_array($id) && isset($id['alias'])) ? $id['alias'] : get_class($this);
$aliases = array($alias, $current);
sort($aliases);
$alias = Inflector::pluralize($aliases[0]) . $aliases[1];
$this->addToMap($alias, $alias);
}
}
}

private function addToMap($alias, $class) {
if (!isset($this->map[$alias])) {
$this->map[$alias] = $class;
}
}
}
?>
87 changes: 87 additions & 0 deletions tests/cases/libs/lazy_model.test.php
@@ -0,0 +1,87 @@
<?php
App::import('Libs', 'LazyModel.LazyModel');
abstract class LazyAppModel extends LazyModel {
}

class Article extends LazyAppModel {
public $belongsTo = array('User');
public $hasAndBelongsToMany = array('Tag');
}

class User extends LazyAppModel {
public $hasMany = array('Article');
}

class Tag extends LazyAppModel {
public $hasAndBelongsToMany = array('Article');
}

class LazyModelTestCase extends CakeTestCase {
public $fixtures = array('core.article', 'core.user', 'core.tag', 'core.articles_tag');

public function testLazyLoadingNonHABTM() {
$user = ClassRegistry::init('User');

$this->assertFalse(property_exists($user, 'Article'));

$user->Article->create();

$this->assertTrue(property_exists($user, 'Article'));
}

public function testLazyLoadingHABTM() {
$article = ClassRegistry::init('Article');

$this->assertTrue(property_exists($article, 'Tag'));
$this->assertTrue(property_exists($article, 'ArticlesTag'));
$this->assertFalse(property_exists($article, 'User'));

$article->User->create();

$this->assertTrue(property_exists($article, 'Tag'));
$this->assertTrue(property_exists($article, 'ArticlesTag'));
$this->assertTrue(property_exists($article, 'User'));
}

public function testNoRecursion() {
$article = ClassRegistry::init('Article');
$results = $article->find('all', array('recursive' => -1));

$this->assertEqual(Set::extract('/Article/id', $results), array(1,2,3));
$this->assertEqual(array_keys($results[0]), array('Article'));
}

public function testRecursionLevel0() {
$article = ClassRegistry::init('Article');
$results = $article->find('all', array('recursive' => 0));

$this->assertEqual(Set::extract('/Article/id', $results), array(1,2,3));
$this->assertEqual(Set::extract('/User/id', $results), array(1,3,1));
$this->assertEqual(array_keys($results[0]), array('Article', 'User'));
}

public function testRecursionLevel1() {
$article = ClassRegistry::init('Article');
$results = $article->find('all', array('recursive' => 1));

$this->assertEqual(Set::extract('/Article/id', $results), array(1,2,3));
$this->assertEqual(Set::extract('/User/id', $results), array(1,3,1));
$this->assertEqual(Set::extract('/0/Tag/id', $results), array(1,2));
$this->assertEqual(array_keys($results[0]), array('Article', 'User', 'Tag'));
}

public function testContainable() {
$user = ClassRegistry::init('User');
$user->Behaviors->attach('Containable');

$results = $user->find('all', array('contain' => array('Article' => array('limit' => 1))));

$this->assertEqual(Set::extract('/Article/id', $results), array(1,2));
$this->assertEqual(array_keys($results[0]), array('User', 'Article'));
}

public function endTest() {
ClassRegistry::flush();
}
}
?>

0 comments on commit 9367858

Please sign in to comment.