/** * Handles constructing the relatedBeansAndModels with special attention to the case where it is PolyOneToMany * @param string $modelClassName * @param mixed $sqlOrBean */ private function constructRelatedBeansAndModels($modelClassName, $sqlOrBean = '') { assert('is_string($sqlOrBean) || $sqlOrBean instanceof RedBean_OODBBean'); $tableName = RedBeanModel::getTableName($modelClassName); if (is_string($sqlOrBean)) { $this->relatedBeansAndModels = array_values($beans = R::find($tableName, $sqlOrBean)); } else { assert('$sqlOrBean instanceof RedBean_OODBBean'); $this->bean = $sqlOrBean; try { if ($this->bean->id > 0) { if ($this->polyName != null) { $value = array(); $values['id'] = $this->bean->id; $values['type'] = $this->bean->getMeta('type'); $this->relatedBeansAndModels = array_values(R::find($tableName, strtolower($this->polyName) . '_id = :id AND ' . strtolower($this->polyName) . '_type = :type', $values)); } else { $relatedIds = ZurmoRedBeanLinkManager::getKeys($this->bean, $tableName); $this->relatedBeansAndModels = array_values(R::batch($tableName, $relatedIds)); } } else { $this->relatedBeansAndModels = array(); } } catch (RedBean_Exception_SQL $e) { // SQLSTATE[42S02]: Base table or view not found... // SQLSTATE[42S22]: Column not found... if (!in_array($e->getSQLState(), array('42S02', '42S22'))) { throw $e; } $this->relatedBeansAndModels = array(); } } }
public static function getTailDistinctEventsByEventName($eventName, User $user, $count) { assert('is_string($eventName)'); assert('is_int($count)'); $sql = "select id\n from ( select id, modelclassname, modelid, datetime from auditevent where _user_id = {$user->id}\n AND eventname = '{$eventName}' order by id desc ) auditevent\n group by concat(modelclassname, modelid) order by datetime desc limit {$count}"; $ids = R::getCol($sql); $beans = R::batch('auditevent', $ids); return self::makeModels($beans, __CLASS__); }
/** * Test missing bean scenarios. * * @return void */ public function testMissingBeans() { testpack('deal with missing beans'); $id = R::store(R::dispense('beer')); $bottles = R::batch('beer', array($id, $id + 1, $id + 2)); asrt(count($bottles), 3); asrt((int) $bottles[$id]->id, (int) $id); asrt((int) $bottles[$id + 1]->id, 0); asrt((int) $bottles[$id + 2]->id, 0); }
/** * Constructs a new RedBeanModels which is a collection of classes extending model. * The models are created lazily. * Models are only constructed with beans by the model. Beans are * never used by the application directly. * The application can construct a new models object by constructing * them without specifying a bean. In other words, if Php had overloading * and friends the constructor without the $bean would be public, and the * constructor taking a bean would private and available only to RedBeanModel. */ public function __construct($modelClassName, $sqlOrBean = '') { assert('is_string($sqlOrBean) || $sqlOrBean instanceof RedBean_OODBBean'); $this->modelClassName = $modelClassName; $this->position = 0; $tableName = RedBeanModel::getTableName($modelClassName); if (is_string($sqlOrBean)) { $this->relatedBeansAndModels = array_values(R::find($tableName, $sqlOrBean)); } else { assert('$sqlOrBean instanceof RedBean_OODBBean'); $this->bean = $sqlOrBean; // I had this... // $this->relatedBeansAndModels = array_values(R::related($this->bean, $tableName)); // and the doco says to use related in place of findLinks which is deprecated, // but that is returning zero when I know there are linked beans. try { // So I'm getting them with the link manager, but that can // throw if the table or column doesn't exist yet because there // are no linked beans. if ($this->bean->id > 0) { $relatedIds = ZurmoRedBeanLinkManager::getKeys($this->bean, $tableName); $this->relatedBeansAndModels = array_values(R::batch($tableName, $relatedIds)); } else { $this->relatedBeansAndModels = array(); } } catch (RedBean_Exception_SQL $e) { // SQLSTATE[42S02]: Base table or view not found... // SQLSTATE[42S22]: Column not found... if (!in_array($e->getSQLState(), array('42S02', '42S22'))) { throw $e; } // If there is nothing yet linked // just have no related models yet. $this->relatedBeansAndModels = array(); } } }
public function loadAll($type, $ids) { return R::batch($type, $ids); }
/** * Given a table name, count, and offset get an array of beans. * @param string $tableName * @param integer $count * @param integer $offset * @return array of RedBean_OODBBean beans. */ public static function getSubset($tableName, $where = null, $count = null, $offset = null) { assert('is_string($tableName)'); assert('$offset === null || is_integer($offset) && $offset >= 0'); assert('$offset === null || is_integer($count) && $count >= 1'); $sql = 'select id from ' . $tableName; if ($where != null) { $sql .= ' where ' . $where; } if ($count !== null) { $sql .= " limit {$count}"; } if ($offset !== null) { $sql .= " offset {$offset}"; } $ids = R::getCol($sql); return R::batch($tableName, $ids); }
/** * Gets a range of models from the database of the named model type. * @param $modelClassName * @param $joinTablesAdapter null or instance of joinTablesAdapter. * @param $offset The zero based index of the first model to be returned. * @param $count The number of models to be returned. * @param $where * @param $orderBy - sql string. Example 'a desc' or 'a.b desc'. Currently only supports non-related attributes * @param $modelClassName Pass only when getting it at runtime gets the wrong name. * @return An array of models of the type of the extending model. */ public static function getSubset(RedBeanModelJoinTablesQueryAdapter $joinTablesAdapter = null, $offset = null, $count = null, $where = null, $orderBy = null, $modelClassName = null, $selectDistinct = false) { assert('$offset === null || is_integer($offset) && $offset >= 0'); assert('$count === null || is_integer($count) && $count >= 1'); assert('$where === null || is_string ($where) && $where != ""'); assert('$orderBy === null || is_string ($orderBy) && $orderBy != ""'); assert('$modelClassName === null || is_string($modelClassName) && $modelClassName != ""'); if ($modelClassName === null) { $modelClassName = get_called_class(); } $ids = self::getSubsetIds($joinTablesAdapter, $offset, $count, $where, $orderBy, $modelClassName, $selectDistinct); $tableName = self::getTableName($modelClassName); $beans = R::batch($tableName, $ids); return self::makeModels($beans, $modelClassName); }
/** * @depends testSetAttributesWithPostForCustomField */ public function testUpdateValueOnCustomFieldRows() { $values = array('A', 'B', 'C'); $customFieldData = CustomFieldData::getByName('updateItems'); $customFieldData->serializedData = serialize($values); $this->assertTrue($customFieldData->save()); $id = $customFieldData->id; $customField = new CustomField(); $customField->value = 'A'; $customField->data = $customFieldData; $this->assertTrue($customField->save()); $customField = new CustomField(); $customField->value = 'B'; $customField->data = $customFieldData; $this->assertTrue($customField->save()); $customField = new CustomField(); $customField->value = 'C'; $customField->data = $customFieldData; $this->assertTrue($customField->save()); $customField = new CustomField(); $customField->value = 'C'; $customField->data = $customFieldData; $this->assertTrue($customField->save()); $quote = DatabaseCompatibilityUtil::getQuote(); $customFieldTableName = RedBeanModel::getTableName('CustomField'); $baseCustomFieldTableName = RedBeanModel::getTableName('BaseCustomField'); $valueAttributeColumnName = 'value'; $dataAttributeColumnName = RedBeanModel::getForeignKeyName('CustomField', 'data'); $sql = "select {$quote}{$customFieldTableName}{$quote}.id from {$quote}{$customFieldTableName}{$quote} "; $sql .= "left join {$quote}{$baseCustomFieldTableName}{$quote} on "; $sql .= "{$quote}{$baseCustomFieldTableName}{$quote}.id = "; $sql .= "{$quote}{$customFieldTableName}{$quote}.basecustomfield_id "; $sql .= "where {$quote}{$dataAttributeColumnName}{$quote} = {$id}"; $ids = R::getCol($sql); $beans = R::batch($customFieldTableName, $ids); $customFields = RedBeanModel::makeModels($beans, 'CustomField'); $this->assertEquals(4, count($customFields)); $sql = "select {$quote}{$customFieldTableName}{$quote}.id from {$quote}{$customFieldTableName}{$quote} "; $sql .= "left join {$quote}{$baseCustomFieldTableName}{$quote} on "; $sql .= "{$quote}{$baseCustomFieldTableName}{$quote}.id = "; $sql .= "{$quote}{$customFieldTableName}{$quote}.basecustomfield_id "; $sql .= "where {$quote}{$dataAttributeColumnName}{$quote} = {$id} "; $sql .= "and {$quote}{$valueAttributeColumnName}{$quote} = 'B'"; $this->assertEquals(1, count(R::getCol($sql))); $sql = "select {$quote}{$customFieldTableName}{$quote}.id from {$quote}{$customFieldTableName}{$quote} "; $sql .= "left join {$quote}{$baseCustomFieldTableName}{$quote} on "; $sql .= "{$quote}{$baseCustomFieldTableName}{$quote}.id = "; $sql .= "{$quote}{$customFieldTableName}{$quote}.basecustomfield_id "; $sql .= "where {$quote}{$dataAttributeColumnName}{$quote} = {$id} "; $sql .= "and {$quote}{$valueAttributeColumnName}{$quote} = 'C'"; $this->assertEquals(2, count(R::getCol($sql))); $sql = "select {$quote}{$customFieldTableName}{$quote}.id from {$quote}{$customFieldTableName}{$quote} "; $sql .= "left join {$quote}{$baseCustomFieldTableName}{$quote} on "; $sql .= "{$quote}{$baseCustomFieldTableName}{$quote}.id = "; $sql .= "{$quote}{$customFieldTableName}{$quote}.basecustomfield_id "; $sql .= "where {$quote}{$dataAttributeColumnName}{$quote} = {$id} "; $sql .= "and {$quote}{$valueAttributeColumnName}{$quote} = 'E'"; $this->assertEquals(0, count(R::getCol($sql))); CustomField::updateValueByDataIdAndOldValueAndNewValue($id, 'C', 'E'); $sql = "select {$quote}{$customFieldTableName}{$quote}.id from {$quote}{$customFieldTableName}{$quote} "; $sql .= "left join {$quote}{$baseCustomFieldTableName}{$quote} on "; $sql .= "{$quote}{$baseCustomFieldTableName}{$quote}.id = "; $sql .= "{$quote}{$customFieldTableName}{$quote}.basecustomfield_id "; $sql .= "where {$quote}{$dataAttributeColumnName}{$quote} = {$id} "; $sql .= "and {$quote}{$valueAttributeColumnName}{$quote} = 'B'"; $this->assertEquals(1, count(R::getCol($sql))); $sql = "select {$quote}{$customFieldTableName}{$quote}.id from {$quote}{$customFieldTableName}{$quote} "; $sql .= "left join {$quote}{$baseCustomFieldTableName}{$quote} on "; $sql .= "{$quote}{$baseCustomFieldTableName}{$quote}.id = "; $sql .= "{$quote}{$customFieldTableName}{$quote}.basecustomfield_id "; $sql .= "where {$quote}{$dataAttributeColumnName}{$quote} = {$id} "; $sql .= "and {$quote}{$valueAttributeColumnName}{$quote} = 'C'"; $this->assertEquals(0, count(R::getCol($sql))); $sql = "select {$quote}{$customFieldTableName}{$quote}.id from {$quote}{$customFieldTableName}{$quote} "; $sql .= "left join {$quote}{$baseCustomFieldTableName}{$quote} on "; $sql .= "{$quote}{$baseCustomFieldTableName}{$quote}.id = "; $sql .= "{$quote}{$customFieldTableName}{$quote}.basecustomfield_id "; $sql .= "where {$quote}{$dataAttributeColumnName}{$quote} = {$id} "; $sql .= "and {$quote}{$valueAttributeColumnName}{$quote} = 'E'"; $this->assertEquals(2, count(R::getCol($sql))); }
/** * Preloads certain properties for beans. * Understands aliases. * * Usage: R::preload($books,array('coauthor'=>'author')); * * @param array $beans beans * @param array $types types to load */ public static function preload($beans, $types) { foreach ($types as $key => $type) { $field = is_numeric($key) ? $type : $key; $ids = array(); foreach ($beans as $bean) { $id = $bean->{$field . '_id'}; $ids[] = $id; $map[$id] = $bean; } $parents = R::batch($type, $ids); foreach ($parents as $parent) { $map[$parent->id]->setProperty($field, $parent); } } }
/** * Test effects of cache. * * @return void */ public function testCachingEffects() { testpack('Testing WriteCache Query Writer Cache'); $logger = RedBean_Plugin_QueryLogger::getInstanceAndAttach(R::$adapter); $book = R::dispense('book')->setAttr('title', 'ABC'); $book->ownPage[] = R::dispense('page'); $id = R::store($book); // Test load cache -- without $logger->clear(); $book = R::load('book', $id); $book = R::load('book', $id); asrt(count($logger->grep('SELECT')), 2); // With cache R::useWriterCache(TRUE); $logger->clear(); $book = R::load('book', $id); $book = R::load('book', $id); asrt(count($logger->grep('SELECT')), 1); R::useWriterCache(FALSE); // Test find cache $logger->clear(); $book = R::find('book'); $book = R::find('book'); asrt(count($logger->grep('SELECT')), 2); // With cache R::$writer->setUseCache(TRUE); $logger->clear(); $book = R::find('book'); $book = R::find('book'); asrt(count($logger->grep('SELECT')), 1); R::$writer->setUseCache(FALSE); // Test combinations $logger->clear(); $book = R::findOne('book', ' id = ? ', array($id)); $book->ownPage; R::batch('book', array($id)); $book = R::findOne('book', ' id = ? ', array($id)); $book->ownPage; R::batch('book', array($id)); asrt(count($logger->grep('SELECT')), 6); // With cache R::$writer->setUseCache(TRUE); $logger->clear(); R::batch('book', array($id)); $book = R::findOne('book', ' id = ? ', array($id)); $book->ownPage; $book = R::findOne('book', ' id = ? ', array($id)); $book->ownPage; asrt(count($logger->grep('SELECT')), 3); R::$writer->setUseCache(FALSE); // Test auto flush $logger->clear(); $book = R::findOne('book'); $book->name = 'X'; R::store($book); $book = R::findOne('book'); asrt(count($logger->grep('SELECT *')), 2); // With cache R::$writer->setUseCache(TRUE); $logger->clear(); $book = R::findOne('book'); $book->name = 'Y'; // Will flush R::store($book); $book = R::findOne('book'); // Now the same, auto flushed asrt(count($logger->grep('SELECT *')), 2); R::$writer->setUseCache(FALSE); // Test whether delete flushes as well (because uses selectRecord - might be a gotcha!) R::store(R::dispense('garbage')); $garbage = R::findOne('garbage'); $logger->clear(); $book = R::findOne('book'); R::trash($garbage); $book = R::findOne('book'); asrt(count($logger->grep('SELECT *')), 2); R::store(R::dispense('garbage')); $garbage = R::findOne('garbage'); // With cache R::$writer->setUseCache(TRUE); $logger->clear(); $book = R::findOne('book'); R::trash($garbage); $book = R::findOne('book'); // Now the same, auto flushed asrt(count($logger->grep('SELECT *')), 2); R::$writer->setUseCache(FALSE); R::store(R::dispense('garbage')); $garbage = R::findOne('garbage'); // With cache R::$writer->setUseCache(TRUE); $logger->clear(); $book = R::findOne('book'); R::$writer->queryRecord('garbage', array('id' => array($garbage->id))); $book = R::findOne('book'); // Now the same, auto flushed asrt(count($logger->grep('SELECT *')), 2); }
R::transaction(function () use(&$task) { R::store($task); }); go_home(); break; case 'editwork': if (!isset($_POST['tasks'])) { go_home(); } R::transaction(function () use(&$currentPeriod, &$currentTeam) { $nextPeriod = FALSE; if ($currentPeriod) { $nextPeriod = reset($currentTeam->withCondition('start>=? ORDER BY start ASC LIMIT 1', array($currentPeriod->end))->ownPeriodList); $prevPeriod = reset($currentTeam->withCondition('end<=? ORDER BY end DESC LIMIT 1', array($currentPeriod->start))->ownPeriodList); } foreach (R::batch('task', $_POST['tasks']) as $task) { if ($_POST['operation'] === 'next' && $nextPeriod) { R::store($task->setAttr('period', $nextPeriod)); } elseif ($_POST['operation'] === 'prev' && $prevPeriod) { R::store($task->setAttr('period', $prevPeriod)); } elseif ($_POST['operation'] === 'nextcopy' && $nextPeriod) { R::store($task->setAttr('id', 0)->setAttr('period', $nextPeriod)); } elseif ($_POST['operation'] === 'done') { R::store($task->import(array('done' => 1, 'progress' => 100))); } elseif ($_POST['operation'] === 'notdone') { R::store($task->import(array('done' => 0, 'progress' => 0))); } } }); go_home(); break;
/** * Test for issue #328 (excerpt): * Previously, if we wanted to use the array form without an SQL snippet, it will fail: * R::preload($beans, array('manager' => array('people'))); * It fixes the ability to have conditional snippets without bindings: * R::preload($beans, array('ownManager' => array('manager', array("name = 'john'")))) * * @return void */ public function testAPreloadWithMissingParams() { testpack('Test flexible method signature (issue #328).'); R::nuke(); $beans = R::dispense('user', 2); foreach ($beans as $bean) { $bean->people = R::dispense('manager'); } R::storeAll($beans); R::preload($beans, array('manager' => array('people'))); R::nuke(); $beans = R::dispense('company', 2); foreach ($beans as $company) { $company->ownManager[] = R::dispense('manager')->setAttr('name', 'John'); } $ids = R::storeAll($beans); $beans = R::batch('company', $ids); R::preload($beans, array('ownManager' => array('manager', array("name = 'John'")))); $bean = reset($beans); $manager = reset($bean->ownManager); asrt($manager->name, 'John'); }
asrt($book->id !== $book2->id, true); asrt($book->title, $book2->title); testpack("Test Swap function in R-facade"); $book = R::dispense("book"); $book->title = "firstbook"; $book->rating = 2; $id1 = R::store($book); $book = R::dispense("book"); $book->title = "secondbook"; $book->rating = 3; $id2 = R::store($book); $book1 = R::load("book", $id1); $book2 = R::load("book", $id2); asrt($book1->rating, '2'); asrt($book2->rating, '3'); $books = R::batch("book", array($id1, $id2)); R::swap($books, "rating"); $book1 = R::load("book", $id1); $book2 = R::load("book", $id2); asrt($book1->rating, '3'); asrt($book2->rating, '2'); testpack("Test R::convertToBeans"); $SQL = "SELECT '1' as id, a.name AS name, b.title AS title, '123' as rating FROM author AS a LEFT JOIN book as b ON b.id = ? WHERE a.id = ? "; $rows = R::$adapter->get($SQL, array($id2, $aid)); $beans = R::convertToBeans("something", $rows); $bean = reset($beans); asrt($bean->getMeta("type"), "something"); asrt($bean->name, "Bobby"); asrt($bean->title, "secondbook"); asrt($bean->rating, "123"); testpack("Ext Assoc with facade and findRelated");
/** * Test trashAll(). */ public function testMultiDeleteUpdate() { testpack('test multi delete and multi update'); $beans = R::dispenseLabels('bean', array('a', 'b')); $ids = R::storeAll($beans); asrt((int) R::count('bean'), 2); R::trashAll(R::batch('bean', $ids)); asrt((int) R::count('bean'), 0); testpack('test assocManager check'); $rb = new RedBean_OODB(R::$writer); try { $rb->getAssociationManager(); fail(); } catch (RedBean_Exception_Security $e) { pass(); } }
/** * Basic tests through Facade. * * @return void */ public function testBasicThroughFacade() { $toolbox = R::$toolbox; $adapter = $toolbox->getDatabaseAdapter(); $writer = $toolbox->getWriter(); $redbean = $toolbox->getRedBean(); $pdo = $adapter->getDatabase(); $a = new RedBean_AssociationManager($toolbox); asrt(R::$redbean instanceof RedBean_OODB, TRUE); asrt(R::$toolbox instanceof RedBean_Toolbox, TRUE); asrt(R::$adapter instanceof RedBean_Adapter, TRUE); asrt(R::$writer instanceof RedBean_QueryWriter, TRUE); $book = R::dispense("book"); asrt($book instanceof RedBean_OODBBean, TRUE); $book->title = "a nice book"; $id = R::store($book); asrt($id > 0, TRUE); $book = R::load("book", (int) $id); asrt($book->title, "a nice book"); $author = R::dispense("author"); $author->name = "me"; R::store($author); $book9 = R::dispense("book"); $author9 = R::dispense("author"); $author9->name = "mr Nine"; $a9 = R::store($author9); $book9->author_id = $a9; $bk9 = R::store($book9); $book9 = R::load("book", $bk9); $author = R::load("author", $book9->author_id); asrt($author->name, "mr Nine"); R::trash($author); R::trash($book9); pass(); $book2 = R::dispense("book"); $book2->title = "second"; R::store($book2); R::associate($book, $book2); asrt(count(R::related($book, "book")), 1); $book3 = R::dispense("book"); $book3->title = "third"; R::store($book3); R::associate($book, $book3); asrt(count(R::related($book, "book")), 2); asrt(count(R::find("book")), 3); asrt(count(R::findAll("book")), 3); asrt(count(R::findAll("book", " WHERE ROWNUM <= 2")), 2); asrt(count(R::find("book", " id=id ")), 3); asrt(count(R::find("book", " title LIKE ?", array("third"))), 1); asrt(count(R::find("book", " title LIKE ?", array("%d%"))), 2); // Now with new SQL Helper argument asrt(count(R::find("book", R::$f->begin()->addSQL('title LIKE ? ')->put('third'))), 1); asrt(count(R::find("book", R::$f->begin()->addSQL('title LIKE ? ')->put('%d%'))), 2); asrt(count(R::find("book", R::$f->begin()->addSQL('title')->like(' ? ')->addSQL(' ORDER BY id ')->desc()->put('%d%'))), 2); //Find without where clause asrt(count(R::findAll('book', ' order by id')), 3); R::unassociate($book, $book2); asrt(count(R::related($book, "book")), 1); R::trash($book3); R::trash($book2); asrt(count(R::related($book, "book")), 0); asrt(count(R::getAll("SELECT * FROM book ")), 1); asrt(count(R::getCol("SELECT title FROM book ")), 1); asrt((int) R::getCell("SELECT 123 FROM DUAL "), 123); $book = R::dispense("book"); $book->title = "not so original title"; $author = R::dispense("author"); $author->name = "Bobby"; R::store($book); $aid = R::store($author); R::associate($book, $author); $author = R::findOne("author", " name = ? ", array("Bobby")); $books = R::related($author, "book"); $book = reset($books); testpack("Test Swap function in R-facade"); $book = R::dispense("book"); $book->title = "firstbook"; $book->rating = 2; $id1 = R::store($book); $book = R::dispense("book"); $book->title = "secondbook"; $book->rating = 3; $id2 = R::store($book); $book1 = R::load("book", $id1); $book2 = R::load("book", $id2); asrt($book1->rating, '2'); asrt($book2->rating, '3'); $books = R::batch("book", array($id1, $id2)); R::swap($books, "rating"); $book1 = R::load("book", $id1); $book2 = R::load("book", $id2); asrt($book1->rating, '3'); asrt($book2->rating, '2'); testpack("Test R::convertToBeans"); $SQL = "SELECT '1' as id, a.name AS name, b.title AS title, '123' as rating FROM author a LEFT JOIN book b ON b.id = ? WHERE a.id = ? "; $rows = R::$adapter->get($SQL, array($id2, $aid)); $beans = R::convertToBeans("something", $rows); $bean = reset($beans); asrt($bean->getMeta("type"), "something"); asrt($bean->name, "Bobby"); asrt($bean->title, "secondbook"); asrt($bean->rating, "123"); testpack("Ext Assoc with facade and findRelated"); R::nuke(); $cd = R::dispense("cd"); $cd->title = "Midnight Jazzfest"; R::store($cd); $track = R::dispense("track"); $track->title = "Night in Tunesia"; $track2 = R::dispense("track"); $track2->title = "Stompin at one o clock"; $track3 = R::dispense("track"); $track3->title = "Nightlife"; R::store($track); R::store($track2); R::store($track3); // Assoc ext with json R::associate($track, $cd, '{"order":1}'); pass(); // Width array R::associate($track2, $cd, array("order" => 2)); pass(); R::associate($track3, $cd, '{"order":3}'); pass(); $tracks = R::related($cd, "track", " title LIKE ? ", array("Night%")); asrt(count($tracks), 2); $track = array_pop($tracks); asrt(strpos($track->title, "Night") === 0, TRUE); $track = array_pop($tracks); asrt(strpos($track->title, "Night") === 0, TRUE); $track = R::dispense("track"); $track->title = "test"; R::associate($track, $cd, "this column should be named extra"); asrt(R::getCell("SELECT count(*) FROM cd_track WHERE extra = 'this column should be named extra' "), "1"); $composer = R::dispense("performer"); $composer->name = "Miles Davis"; R::store($composer); }