diff --git a/RedBean/OODB.php b/RedBean/OODB.php index bbb0c5e0f..46b9e3ef5 100755 --- a/RedBean/OODB.php +++ b/RedBean/OODB.php @@ -895,25 +895,52 @@ public function setDepList($dep) { */ public function preload($beans, $types) { foreach($types as $key => $type) { - $map = array(); - $field = (is_numeric($key)) ? $type : $key; - $ids = array(); - foreach($beans as $bean) { - if($id = $bean->{$field.'_id'}){ + $map = $ids = array(); + $field = (is_numeric($key)) ? $type : $key;//use an alias? + $filteredBeans = $beans; + while($p = strpos($field,'.')) { //filtering: find the right beans in the path + $nesting = substr($field,0,$p); + $filtered = array(); + foreach($filteredBeans as $bean) { + if (is_array($bean->$nesting)) { + $filtered = array_merge($filtered,$bean->$nesting); + } elseif (!is_null($bean->$nesting)) { + $filtered[] = $bean->$nesting; + } + } + $filteredBeans = $filtered; + $field = substr($field,$p+1); + } + if (strpos($type,'.')) $type = $field; + foreach($filteredBeans as $bean) { //gather ids to load the desired bean collections + if (strpos($field,'own')===0) { //based on bean->id for ownlist + $id = $bean->id; + $ids[$id] = $id; + } elseif($id = $bean->{$field.'_id'}){ //based on bean_id for parent $ids[$id] = $id; if (!isset($map[$id])) $map[$id] = array(); $map[$id][] = $bean; } } - $parents = $this->batch($type,$ids); - foreach($parents as $parent) { - foreach($map[$parent->id] as $childBean) { - $childBean->setProperty($field,$parent); + if (strpos($field,'own')===0) {//preload for own-list using find + $link = $bean->getMeta('type').'_id'; + $children = $this->find($type,array($link=>$ids)); + foreach($filteredBeans as $bean) { + $list = array(); + foreach($children as $child) { + if ($child->$link==$bean->id) $list[$child->id] = $child; + } + $bean->setProperty($field,$list); } - } + } else { //preload for parent objects using batch() + foreach($this->batch($type,$ids) as $parent) { + foreach($map[$parent->id] as $childBean) { + $childBean->setProperty($field,$parent); + } + } + } } } - } diff --git a/testing/RedUNIT/Base/Preloading.php b/testing/RedUNIT/Base/Preloading.php index adc5a57fa..43b0ef3e9 100644 --- a/testing/RedUNIT/Base/Preloading.php +++ b/testing/RedUNIT/Base/Preloading.php @@ -149,6 +149,96 @@ public function run() { asrt($item->author->name,'John'); } + //test nested bean preloading + R::nuke(); + $authors = R::dispense('author',2); + foreach($authors as $author) { + $author->ownBook = R::dispense('book',2); + foreach($author->ownBook as $book) { + $book->ownPage = R::dispense('page',2); + foreach($book->ownPage as $page) $page->ownText = R::dispense('text',1); + } + } + R::storeAll($authors); + $texts = R::find('text'); + R::nuke(); + $text = reset($texts); + asrt(($text->page),null); + + //now with preloading + R::nuke(); + $authors = R::dispense('author',2); + foreach($authors as $author) { + $author->ownBook = R::dispense('book',2); + foreach($author->ownBook as $book) { + $book->ownPage = R::dispense('page',2); + foreach($book->ownPage as $page) $page->ownText = R::dispense('text',2); + } + } + R::storeAll($authors); + $texts = R::find('text'); + R::preload($texts,array('page','page.book','page.book.author')); + R::nuke(); + $text = reset($texts); + asrt(($text->page->id)>0,true); + asrt(($text->page->book->id)>0,true); + asrt(($text->page->book->author->id)>0,true); + + R::nuke(); + $authors = R::dispense('author',2); + foreach($authors as $author) { + $author->alias('coauthor')->ownBook = R::dispense('book',2); + foreach($author->alias('coauthor')->ownBook as $book) { + $book->ownPage = R::dispense('page',2); + foreach($book->ownPage as $page) $page->ownText = R::dispense('text',2); + } + } + R::storeAll($authors); + $texts = R::find('text'); + R::preload($texts,array('page','page.book','page.book.coauthor'=>'author')); + R::nuke(); + $text = reset($texts); + asrt(($text->page->id)>0,true); + asrt(($text->page->book->id)>0,true); + asrt(($text->page->book->fetchAs('author')->coauthor->id)>0,true); + + //now test preloading of own-lists + R::nuke(); + $authors = R::dispense('author',2); + foreach($authors as $author) { + $author->ownBook = R::dispense('book',2); + foreach($author->ownBook as $book) { + $book->ownPage = R::dispense('page',2); + foreach($book->ownPage as $page) $page->ownText = R::dispense('text',2); + } + } + R::storeAll($authors); + $authors = R::find('author'); + R::preload($authors,array('ownBook'=>'book','ownBook.ownPage'=>'page','ownBook.ownPage.ownText'=>'text')); + R::nuke(); + $author = reset($authors); + asrt(count($author->ownBook),2); + $book = reset($author->ownBook); + asrt(count($book->ownPage),2); + $page = reset($book->ownPage); + asrt(count($page->ownText),2); + + //now test with empty beans + $authors = R::dispense('author',2); + R::storeAll($authors); + $authors = R::find('author'); + R::preload($authors,array('ownBook'=>'book','ownBook.ownPage'=>'page','ownBook.ownPage.ownText'=>'text')); + $author = reset($authors); + asrt(count($author->ownBook),0); + + $texts = R::dispense('text',2); + R::storeAll($texts); + $texts = R::find('text'); + R::preload($texts,array('page','page.book')); + $text = reset($texts); + asrt($text->page,null); + + } } \ No newline at end of file