- All beans in own-lists will be duplicated as well
- All references to shared beans will be copied but not the shared beans themselves
- All references to parent objects (_id fields) will be copied but not the parents themselves
In most cases this is the desired scenario for copying beans.
This function uses a trail-array to prevent infinite recursion, if a recursive bean is found
(i.e. one that already has been processed) the ID of the bean will be returned.
This should not happen though.
Note:
This function does a reflectional database query so it may be slow.
/** * In the past it was not possible to export beans * like 'feed' (Model_Feed). * * @return void */ public function testExportIssue() { R::nuke(); $feed = R::dispense('feed'); $feed->post = array('first', 'second'); R::store($feed); $rows = R::getAll('SELECT * FROM feed'); asrt($rows[0]['post'], '["first","second"]'); $feed = $feed->fresh(); asrt(is_array($feed->post), TRUE); asrt($feed->post[0], 'first'); asrt($feed->post[1], 'second'); R::store($feed); $rows = R::getAll('SELECT * FROM feed'); asrt($rows[0]['post'], '["first","second"]'); $feed = R::load('feed', $feed->id); $feed->post[] = 'third'; R::store($feed); $rows = R::getAll('SELECT * FROM feed'); asrt($rows[0]['post'], '["first","second","third"]'); $feed = $feed->fresh(); asrt(is_array($feed->post), TRUE); asrt($feed->post[0], 'first'); asrt($feed->post[1], 'second'); asrt($feed->post[2], 'third'); //now the catch: can we use export? //PHP Fatal error: Call to a member function export() on a non-object $feeds = R::exportAll(R::find('feed')); asrt(is_array($feeds), TRUE); $feed = reset($feeds); asrt($feed['post'][0], 'first'); asrt($feed['post'][1], 'second'); asrt($feed['post'][2], 'third'); //can we also dup()? $feedOne = R::findOne('feed'); R::store(R::dup($feedOne)); asrt(R::count('feed'), 2); //can we delete? R::trash($feedOne); asrt(R::count('feed'), 1); $feedTwo = R::findOne('feed'); $feed = $feedTwo->export(); asrt($feed['post'][0], 'first'); asrt($feed['post'][1], 'second'); asrt($feed['post'][2], 'third'); }
/** * Test basic CRUD operations. */ public function testBasicOperations() { //Can we dispense a naughty bean? (with underscore) $author = R::xdispense(AUTHOR); asrt($author instanceof OODBBean, TRUE); asrt($author->getMeta('type'), AUTHOR); $author->name = 'Mr. Quill'; $book = R::xdispense(BOOK); asrt($book instanceof OODBBean, TRUE); asrt($book->getMeta('type'), BOOK); $book->title = 'Good Stories'; $friend = R::xdispense(FRIEND); $friend->name = 'Muse'; asrt($friend instanceof OODBBean, TRUE); asrt($friend->getMeta('type'), FRIEND); $publisher = R::xdispense(PUBLISHER); $publisher->name = 'Good Books'; asrt($publisher instanceof OODBBean, TRUE); asrt($publisher->getMeta('type'), PUBLISHER); asrt(is_array($author->{BOOKLIST}), TRUE); //add books to the book list using the constant $author->{BOOKLIST}[] = $book; asrt(count($author->{BOOKLIST}), 1); //can we also add friends? (N-M) $author->{FRIENDLIST}[] = $friend; $author->{PUBLISHER} = $publisher; $id = R::store($author); asrt($id > 0, TRUE); $author = $author->fresh(); //Can we add another friend after reload? $author->{FRIENDLIST}[] = R::xdispense(FRIEND)->setAttr('name', 'buddy'); R::store($author); $author = $author->fresh(); //Now check the contents of the bean, its lists (books,friends) and parent (publisher) asrt($author->name, 'Mr. Quill'); asrt(count($author->{BOOKLIST}), 1); $firstBook = reset($author->{BOOKLIST}); asrt($firstBook->title, 'Good Stories'); asrt(count($author->{FRIENDLIST}), 2); $firstFriend = reset($author->{FRIENDLIST}); $parent = $author->{PUBLISHER}; asrt($parent instanceof OODBBean, TRUE); $tables = R::inspect(); //have all tables been prefixed? foreach ($tables as $table) { asrt(strpos($table, 'tbl_'), 0); } //Can we make an export? $export = R::exportAll(R::findOne(AUTHOR), TRUE); $export = reset($export); asrt(isset($export[PUBLISHER]), TRUE); asrt(isset($export[BOOKLIST]), TRUE); asrt(isset($export[FRIENDLIST]), TRUE); asrt(isset($export['ownBook']), FALSE); asrt(isset($export['sharedFriend']), FALSE); asrt(isset($export['publisher']), FALSE); //Can we duplicate? $copy = R::dup($author); $copy->name = 'Mr. Clone'; R::store($copy); $copy = $copy->fresh(); asrt($copy->name, 'Mr. Clone'); asrt(count($copy->{BOOKLIST}), 1); $firstBook = reset($copy->{BOOKLIST}); asrt($firstBook->title, 'Good Stories'); asrt(count($copy->{FRIENDLIST}), 2); $firstFriend = reset($copy->{FRIENDLIST}); $parent = $copy->{PUBLISHER}; asrt($parent instanceof OODBBean, TRUE); //Can we count? asrt(R::count(AUTHOR), 2); $copy = $copy->fresh(); asrt($copy->countOwn(BOOK), 1); asrt($copy->countShared(FRIEND), 2); //Can we delete? R::trash($author); asrt(R::count(AUTHOR), 1); //Can we nuke? R::nuke(); asrt(R::count(AUTHOR), 0); asrt(count(R::inspect()), 0); }
/** * Instead of overriding this method, override methods * called by this (beforeUpdate,Save,Create and validatesOnCreate,Save,Update) * This method won't get called when R::store() called when no change to instance is made. * @throws \Exception */ public final function update() { if (!$this->validates()) { throw new \Exception($this->errorMessage()); } else { $this->actionsBefore(); } $this->oldMe = R::dup($this->unbox(), array(), true); }
/** * Test Full fluid UUID support. * */ public function testFullSupport() { //Rewire objects to support UUIDs. $oldToolBox = R::getToolBox(); $oldAdapter = $oldToolBox->getDatabaseAdapter(); $uuidWriter = new \UUIDWriterPostgres($oldAdapter); $newRedBean = new OODB($uuidWriter); $newToolBox = new ToolBox($newRedBean, $oldAdapter, $uuidWriter); R::configureFacadeWithToolbox($newToolBox); list($mansion, $rooms, $ghosts, $key) = R::dispenseAll('mansion,room*3,ghost*4,key'); $mansion->name = 'Haunted Mansion'; $mansion->xownRoomList = $rooms; $rooms[0]->name = 'Green Room'; $rooms[1]->name = 'Red Room'; $rooms[2]->name = 'Blue Room'; $ghosts[0]->name = 'zero'; $ghosts[1]->name = 'one'; $ghosts[2]->name = 'two'; $ghosts[3]->name = 'three'; $rooms[0]->noLoad()->sharedGhostList = array($ghosts[0], $ghosts[1]); $rooms[1]->noLoad()->sharedGhostList = array($ghosts[0], $ghosts[2]); $rooms[2]->noLoad()->sharedGhostList = array($ghosts[1], $ghosts[3], $ghosts[2]); $rooms[2]->xownKey = array($key); //Can we store a bean hierachy with UUIDs? R::debug(1); $id = R::store($mansion); //exit; asrt(is_string($id), TRUE); asrt(strlen($id), 36); $haunted = R::load('mansion', $id); asrt($haunted->name, 'Haunted Mansion'); asrt(is_string($haunted->id), TRUE); asrt(strlen($haunted->id), 36); asrt(is_array($haunted->xownRoomList), TRUE); asrt(count($haunted->ownRoom), 3); $rooms = $haunted->xownRoomList; //Do some counting... $greenRoom = NULL; foreach ($rooms as $room) { if ($room->name === 'Green Room') { $greenRoom = $room; break; } } asrt(!is_null($greenRoom), TRUE); asrt(is_array($greenRoom->with(' ORDER BY id ')->sharedGhostList), TRUE); asrt(count($greenRoom->sharedGhostList), 2); $names = array(); foreach ($greenRoom->sharedGhost as $ghost) { $names[] = $ghost->name; } sort($names); $names = implode(',', $names); asrt($names, 'one,zero'); $rooms = $haunted->xownRoomList; $blueRoom = NULL; foreach ($rooms as $room) { if ($room->name === 'Blue Room') { $blueRoom = $room; break; } } asrt(!is_null($blueRoom), TRUE); asrt(is_array($blueRoom->sharedGhostList), TRUE); asrt(count($blueRoom->sharedGhostList), 3); $names = array(); foreach ($blueRoom->sharedGhost as $ghost) { $names[] = $ghost->name; } sort($names); $names = implode(',', $names); asrt($names, 'one,three,two'); $rooms = $haunted->xownRoomList; $redRoom = NULL; foreach ($rooms as $room) { if ($room->name === 'Red Room') { $redRoom = $room; break; } } $names = array(); foreach ($redRoom->sharedGhost as $ghost) { $names[] = $ghost->name; } sort($names); $names = implode(',', $names); asrt($names, 'two,zero'); asrt(!is_null($redRoom), TRUE); asrt(is_array($redRoom->sharedGhostList), TRUE); asrt(count($redRoom->sharedGhostList), 2); //Can we repaint a room? $redRoom->name = 'Yellow Room'; $id = R::store($redRoom); $yellowRoom = R::load('room', $id); asrt($yellowRoom->name, 'Yellow Room'); asrt(!is_null($yellowRoom), TRUE); asrt(is_array($yellowRoom->sharedGhostList), TRUE); asrt(count($yellowRoom->sharedGhostList), 2); //Can we throw one ghost out? array_pop($yellowRoom->sharedGhost); R::store($yellowRoom); $yellowRoom = $yellowRoom->fresh(); asrt($yellowRoom->name, 'Yellow Room'); asrt(!is_null($yellowRoom), TRUE); asrt(is_array($yellowRoom->sharedGhostList), TRUE); asrt(count($yellowRoom->sharedGhostList), 1); //can we remove one of the rooms? asrt(R::count('key'), 1); $list = $mansion->withCondition(' "name" = ? ', array('Blue Room'))->xownRoomList; $room = reset($list); unset($mansion->xownRoomList[$room->id]); R::store($mansion); asrt(R::count('room'), 2); //and what about its dependent beans? asrt(R::count('key'), 0); asrt(R::count('ghost_room'), 3); //and can we find ghosts? $ghosts = R::find('ghost'); asrt(count($ghosts), 4); $ghosts = R::findAll('ghost', 'ORDER BY id'); asrt(count($ghosts), 4); $ghosts = R::findAll('ghost', 'ORDER BY id LIMIT 2'); asrt(count($ghosts), 2); $ghostZero = R::findOne('ghost', ' "name" = ? ', array('zero')); asrt($ghostZero instanceof OODBBean, TRUE); //can we create link properties on existing tables? $blackRoom = R::dispense('room'); $blackRoom->name = 'Black Room'; $ghostZero->link('ghost_room', array('mood' => 'grumpy'))->room = $blackRoom; R::store($ghostZero); $ghostZero = $ghostZero->fresh(); $list = $ghostZero->sharedRoomList; asrt(count($list), 3); $ghostZero = $ghostZero->fresh(); $list = $ghostZero->withCondition(' ghost_room.mood = ? ', array('grumpy'))->sharedRoomList; asrt(count($list), 1); //can we load a batch? $ids = R::getCol('SELECT id FROM ghost'); $ghosts = R::batch('ghost', $ids); asrt(count($ghosts), 4); //can we do an aggregation? $ghosts = $greenRoom->aggr('ownGhostRoom', 'ghost', 'ghost'); asrt(count($ghosts), 2); //can we duplicate the mansion? asrt(R::count('mansion'), 1); asrt(R::count('room'), 3); asrt(R::count('ghost'), 4); $copy = R::dup($mansion); R::store($copy); asrt(R::count('mansion'), 2); asrt(R::count('room'), 5); //black room does not belong to mansion 1 asrt(R::count('ghost'), 4); //can we do some counting using the list? asrt($copy->countOwn('room'), 2); $rooms = $copy->withCondition(' "name" = ? ', array('Green Room'))->xownRoomList; $room = reset($rooms); asrt($room->countShared('ghost'), 2); //Finally restore old toolbox R::configureFacadeWithToolbox($oldToolBox); }
/** * Run tests */ private function runOnce($n = TRUE) { $books = R::dispense('book', 10); $pages = R::dispense('page', 10); $readers = R::dispense('reader', 10); $texts = R::dispense('text', 10); $i = 0; foreach ($books as $book) { $book->name = 'book-' . $i++; } $i = 0; foreach ($pages as $page) { $page->name = 'page-' . $i++; } $i = 0; foreach ($readers as $reader) { $reader->name = 'reader-' . $i++; } $i = 0; foreach ($texts as $text) { $text->content = 'lorem ipsum -' . $i++; } foreach ($texts as $text) { $pages[array_rand($pages)]->ownText[] = $text; } foreach ($pages as $page) { $books[array_rand($books)]->ownPage[] = $page; } foreach ($readers as $reader) { $books[array_rand($books)]->sharedReader[] = $reader; } $i = $noOfReaders = $noOfPages = $noOfTexts = 0; foreach ($books as $key => $book) { $i++; $noOfPages += count($book->ownPage); $noOfReaders += count($book->sharedReader); foreach ($book->ownPage as $page) { $noOfTexts += count($page->ownText); } $arr = R::exportAll($book); echo "\nIntermediate info: " . json_encode($arr) . ": Totals = {$i},{$noOfPages},{$noOfReaders},{$noOfTexts} "; $this->compare($book, $arr[0]); $copiedBook = R::dup($book); $copiedBookArray = R::exportAll($copiedBook); $this->compare($book, $copiedBookArray[0]); $copiedBookArrayII = $copiedBook->export(); $this->compare($book, $copiedBookArrayII); $copyFromCopy = R::dup($copiedBook); $copyFromCopyArray = R::exportAll($copyFromCopy); $this->compare($book, $copyFromCopyArray[0]); $copyFromCopyArrayII = $copyFromCopy->export(); $this->compare($book, $copyFromCopyArrayII); $id = R::store($book); $copiedBook = R::dup($book); R::store($book); //should not be damaged $copiedBookArray = R::exportAll($copiedBook); $originalBookArray = R::exportAll($book); $this->compare($copiedBook, $copiedBookArray[0]); $this->compare($book, $originalBookArray[0]); $book = R::load('book', $id); $this->compare($book, $originalBookArray[0]); $copiedBook = R::dup($book); $this->compare($copiedBook, $copiedBook->export()); R::store($copiedBook); $this->compare($copiedBook, $copiedBook->export()); $copyFromCopy = R::dup($copiedBook); $this->compare($copyFromCopy, $copyFromCopy->export()); R::store($copyFromCopy); $newPage = R::dispense('page'); $newPage->name = 'new'; $copyFromCopy->ownPage[] = $newPage; $modifiedCopy = R::dup($copyFromCopy); $exportMod = R::exportAll($modifiedCopy); $this->compare($modifiedCopy, $exportMod[0]); asrt(count($modifiedCopy->ownPage), count($copiedBook->ownPage) + 1); R::store($modifiedCopy); if ($n) { asrt((int) R::getCell('SELECT count(*) FROM book'), $i * 4); asrt((int) R::getCell('SELECT count(*) FROM page'), $noOfPages * 4 + $i); asrt((int) R::getCell('SELECT count(*) FROM text'), $noOfTexts * 4); asrt((int) R::getCell('SELECT count(*) FROM book_reader'), $noOfReaders * 4); asrt((int) R::getCell('SELECT count(*) FROM reader'), $noOfReaders); } } if ($n) { asrt($noOfTexts, 10); asrt($noOfReaders, 10); asrt($noOfPages, 10); asrt($i, 10); } }
/** * Test Recursion */ public function testRecursion() { list($d1, $d2) = R::dispense('document', 2); $page = R::dispense('page'); list($p1, $p2) = R::dispense('paragraph', 2); list($e1, $e2) = R::dispense('excerpt', 2); $id2 = R::store($d2); $p1->name = 'a'; $p2->name = 'b'; $page->title = 'my page'; $page->ownParagraph = array($p1, $p2); $p1->ownExcerpt[] = $e1; $p2->ownExcerpt[] = $e2; $e1->ownDocument[] = $d2; $e2->ownDocument[] = $d1; $d1->ownPage[] = $page; $id1 = R::store($d1); $d1 = R::load('document', $id1); $d = R::dup($d1); $ids = array(); asrt($d instanceof OODBBean, TRUE); asrt(count($d->ownPage), 1); foreach (end($d->ownPage)->ownParagraph as $p) { foreach ($p->ownExcerpt as $e) { $ids[] = end($e->ownDocument)->id; } } sort($ids); asrt((int) $ids[0], 0); asrt((int) $ids[1], $id1); R::store($d); pass(); $phillies = R::dispense('diner'); list($lonelyman, $man, $woman) = R::dispense('guest', 3); $attendant = R::dispense('employee'); $lonelyman->name = 'Bennie Moten'; $man->name = 'Daddy Stovepipe'; $woman->name = 'Mississippi Sarah'; $attendant->name = 'Gus Cannon'; $phillies->sharedGuest = array($lonelyman, $man, $woman); $phillies->ownEmployee[] = $attendant; $props = R::dispense('prop', 2); $props[0]->kind = 'cigarette'; $props[1]->kind = 'coffee'; $thought = R::dispense('thought'); $thought->content = 'Blues'; $thought2 = R::dispense('thought'); $thought2->content = 'Jazz'; $woman->ownProp[] = $props[0]; $man->sharedProp[] = $props[1]; $attendant->ownThought = array($thought, $thought2); R::store($phillies); $diner = R::findOne('diner'); $diner2 = R::dup($diner); $id2 = R::store($diner2); $diner2 = R::load('diner', $id2); asrt(count($diner->ownEmployee), 1); asrt(count($diner2->ownEmployee), 1); asrt(count($diner->sharedGuest), 3); asrt(count($diner2->sharedGuest), 3); $employee = reset($diner->ownEmployee); asrt(count($employee->ownThought), 2); $employee = reset($diner2->ownEmployee); asrt(count($employee->ownThought), 2); // Can we change something in the duplicate without changing the original? $employee->name = 'Marvin'; $thought = R::dispense('thought'); $thought->content = 'depression'; $employee->ownThought[] = $thought; array_pop($diner2->sharedGuest); $guest = reset($diner2->sharedGuest); $guest->name = 'Arthur Dent'; $id2 = R::store($diner2); $diner2 = R::load('diner', $id2); asrt(count($diner->ownEmployee), 1); asrt(count($diner2->ownEmployee), 1); asrt(count($diner->sharedGuest), 3); asrt(count($diner2->sharedGuest), 2); $employeeOld = reset($diner->ownEmployee); asrt(count($employeeOld->ownThought), 2); $employee = reset($diner2->ownEmployee); asrt(count($employee->ownThought), 3); asrt($employee->name, 'Marvin'); asrt($employeeOld->name, 'Gus Cannon'); // However the shared beans must not be copied asrt(R::count('guest'), 3); asrt(R::count('guest_prop'), 1); $arthur = R::findOne('guest', ' ' . R::getWriter()->esc('name') . ' = ? ', array('Arthur Dent')); asrt($arthur->name, 'Arthur Dent'); }