Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

2.0: fix for lazy-loading associated models with Containable #222

Closed
wants to merge 4 commits into from

2 participants

@gjm

In 2.0, if you use containable to dynamically (un)bind models, only models specified with containable are lazy-loaded in callbacks or beahviors.

For example, consider ModelA witch belongsTo ModelB and ModelC. If, in a controller, we do:

$this->ModelA->find('all', array('contain' => 'ModelB'));

and, in a callback, we need to access ModelC we get an error saying ModelC is defined.

This fix, besides checking regular associations, checks if a model is present in $__backAssociations and makes it available if it is.

@lorenzo
Owner

I think this makes sense, but a test case would help us a lot merging this patch.

@gjm

Ok but you got to help me on this as i've never done it before (shame on me). Should i make it a part of the core? If so i need to test a model with callbacks. How can i do that? Probably the best would be to create a model in app and write the test against it no?

@lorenzo
Owner

Yes, they need to be in the core. The core tests have lots of pre-made models that you can reuse , or you can add your own. I think a good place would be in the containable behavior tests. Basically create the test model with your callback and run the same thing you did on your app. All the test models are defined in lib/Cake/Test/Case/Model/models.php

@gjm

I've added a test case. Please review it.

@lorenzo
Owner

Thanks for the patch, I had to modify it to fix formatting and remove the changes on gitignore and core.php. Landed in [4adc042]

@lorenzo lorenzo closed this
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
2  .gitignore
@@ -1,7 +1,7 @@
/app/Config
/app/tmp
-/lib/Cake/Console/Templates/skel/tmp/
/plugins
/vendors
.DS_Store
tags
+*~
View
4 app/Config/core.php
@@ -184,12 +184,12 @@
/**
* A random string used in security hashing methods.
*/
- Configure::write('Security.salt', 'DYhG93b0qyJfIxfs2guVoUubWwvniR2G0FgaC9mi');
+ Configure::write('Security.salt', 'DYhasdASDq23q3ddASDq3wf34543ffsDsfd3C9mi');
/**
* A random numeric string (digits only) used to encrypt/decrypt strings.
*/
- Configure::write('Security.cipherSeed', '76859309657453542496749683645');
+ Configure::write('Security.cipherSeed', '76882873489274247289472929385');
/**
* Apply timestamps with the last modified time to static assets (js, css, images).
View
4 lib/Cake/Model/Model.php
@@ -735,6 +735,10 @@ public function __isset($name) {
if (isset($name, $this->{$type}[$name])) {
$className = empty($this->{$type}[$name]['className']) ? $name : $this->{$type}[$name]['className'];
break;
+ }
+ elseif (isset($name, $this->__backAssociation[$type][$name])) {
+ $className = empty($this->__backAssociation[$type][$name]['className']) ? $name : $this->__backAssociation[$type][$name]['className'];
+ break;
} else if ($type == 'hasAndBelongsToMany') {
foreach ($this->{$type} as $k => $relation) {
if (empty($relation['with'])) {
View
22 lib/Cake/Test/Case/Model/Behavior/ContainableBehaviorTest.php
@@ -3589,6 +3589,28 @@ public function testFindAllReturn() {
}
/**
+ * testContain method
+ *
+ * @return void
+ */
+ public function testLazyLoad() {
+ // Local set up
+ $this->User = ClassRegistry::init('User');
+ $this->User->bindModel(array(
+ 'hasMany' => array('Article', 'ArticleFeatured', 'Comment')
+ ), false);
+
+ try {
+ $this->User->find('first', array('contain' => 'Comment',
+ 'lazyLoad' => true));
+ }
+ catch (Exception $e) {
+ $exceptions = true;
+ }
+ $this->assertTrue(empty($exceptions));
+ }
+
+/**
* containments method
*
* @param mixed $Model
View
15 lib/Cake/Test/Case/Model/models.php
@@ -179,6 +179,21 @@ class User extends CakeTestModel {
* @var array
*/
public $validate = array('user' => 'notEmpty', 'password' => 'notEmpty');
+
+ /**
+ * beforeFind() callback
+ *
+ * @return bool
+ */
+ public function beforeFind ($queryData)
+ {
+ if (!empty($queryData['lazyLoad'])) {
+ if (!isset($this->Article, $this->Comment, $this->ArticleFeatured)) {
+ throw new Exception('Unavailable associations');
+ }
+ }
+ return true;
+ }
}
/**
Something went wrong with that request. Please try again.