Пример #1
0
 public function edit($id)
 {
     $news_model = new NewsModel();
     $news = $news_model->find($id);
     $user_model = new UsersModel();
     $user = $user_model->find($news['user_id']);
     $news['user_name'] = $user['name'];
     $this->assign('news', $news);
     $this->assign('action', 'save');
     $this->display('add');
 }
Пример #2
0
 function get()
 {
     $this->f3 = \Base::instance();
     $this->f3->set('AUTOLOAD', $this->f3->get('AUTOLOAD') . ';app/cortex/');
     $this->f3->set('QUIET', false);
     $this->test = new \Test();
     $dbs = array('sql' => new \DB\SQL('mysql:host=localhost;port=3306;dbname=fatfree', 'fatfree', ''));
     foreach ($dbs as $type => $db) {
         $this->f3->set('DB', $db);
         $this->currentType = $type;
         $this->roundTime = microtime(TRUE) - \Base::instance()->get('timer');
         \AuthorModel::setdown();
         \TagModel::setdown();
         \NewsModel::setdown();
         \AuthorModel::setup();
         \TagModel::setup();
         \NewsModel::setup();
         $this->insert_tags();
         $this->insert_authors();
         $this->insert_news();
         $this->insert_news();
         $news = new \NewsModel();
         // reset timer
         $this->getTime();
         //            $result = $news->find(null,array('limit'=>5000));
         //            $this->test->message($this->getTime()." hydrate 5000 records");
         //            unset($news,$result);
         //            $news = new \NewsModel();
         //            $result = $news->find(null,array('limit' => 1000));
         //            $result[0]->author->name;
         //            $this->test->message($this->getTime()." hydrate 1000 records with 1 relation fixed size");
         //			unset($result);
         $result = $news->find(null, array('limit' => 1000));
         $result[0]->tags2[0];
         $this->test->message($this->getTime() . " hydrate 1000 records with 1 relation random size");
         //            $this->test->message($this->getTime()." hydrate 1000 records with 2 relations random size");
         //            $result = $news->find('author = 11');
         //            $this->test->message($this->getTime()." find news from a specific author(11): ".count($result).' news found');
         //            $result = $news->has('author',array('mail LIKE ?','%.co.uk%'))->find();
         //            $this->test->message($this->getTime()." find news with has condition on author: ".count($result).' news found');
         //        var_dump($this->f3->get('DB')->log());
     }
     $this->f3->set('results', $this->test->results());
 }
Пример #3
0
 function run()
 {
     $test = new \Test();
     /** @var \Base $f3 */
     $f3 = \Base::instance();
     $news = new NewsModel();
     $news->load();
     $dummy = array('title' => 'copy test', 'text' => 'Lorem ipsum dolor sit amet.', 'author' => 1, 'tags' => array(3));
     $f3->set('record1', $dummy);
     $news->copyto('record2');
     $test->expect($f3->exists('record2'), 'copyto: raw record copied to hive');
     $news->reset();
     $news->copyfrom('record1');
     $test->expect($news->title = 'copy test' && ($news->text = 'Lorem ipsum dolor sit amet.'), 'copyfrom: hydrate from hive key');
     $test->expect($news->author instanceof AuthorModel && !$news->author->dry() && $news->tags instanceof \DB\CortexCollection, 'copyfrom: relations hydrated successful');
     $test->expect($news->get('author', true) == 1, 'get raw data from relational field');
     $news->reset();
     $news->copyfrom('record2', 'title;author');
     $test->expect($news->title = 'Responsive Images' && $news->get('author', true) == 2 && $news->text == NULL, 'copyfrom: limit fields with split-able string');
     $news->reset();
     $news->copyfrom('record2', array('title'));
     $test->expect($news->title = 'Responsive Images' && $news->text == NULL, 'copyfrom: limit fields by array');
     $news->reset();
     $news->copyfrom($dummy, function ($fields) {
         return array_intersect_key($fields, array_flip(array('title')));
     });
     $test->expect($news->title = 'copy test', 'copyfrom: copy from array instead of hive key');
     $test->expect($news->title = 'copy test' && $news->text == NULL, 'copyfrom: limit fields by callback function');
     $all = $news->find();
     $allTitle = $all->getAll('title');
     $test->expect(count($allTitle) == 3 && $allTitle[0] == 'Responsive Images' && $allTitle[1] == 'CSS3 Showcase' && $allTitle[2] == 'Touchable Interfaces', 'collection getAll returns all values of selected field');
     $newsByID = $all->getBy('_id');
     $test->expect(array_keys($newsByID) == array(1, 2, 3), 'collection getBy sorts by given field');
     $newsByAuthorID = $all->getBy('author', true);
     $test->expect(array_keys($newsByAuthorID) == array(2, 1) && count($newsByAuthorID[2]) == 2 && count($newsByAuthorID[1]) == 1, 'collection getBy nested sort by author');
     $allTitle = array();
     foreach ($all as $record) {
         $allTitle[] = $record->title;
     }
     $test->expect(count($allTitle) == 3 && $allTitle[0] == 'Responsive Images' && $allTitle[1] == 'CSS3 Showcase' && $allTitle[2] == 'Touchable Interfaces', 'collection is traversable');
     ///////////////////////////////////
     return $test->results();
 }
Пример #4
0
 function run()
 {
     $test = new \Test();
     /** @var \Base $f3 */
     $f3 = \Base::instance();
     $news = new NewsModel();
     $news->load();
     $dummy = array('title' => 'copy test', 'text' => 'Lorem ipsum dolor sit amet.', 'author' => 1, 'tags' => array(3));
     $f3->set('record1', $dummy);
     $news->copyto('record2');
     $test->expect($f3->exists('record2'), 'copyto: raw record copied to hive');
     $news->reset();
     $news->copyfrom('record1');
     $test->expect($news->title = 'copy test' && ($news->text = 'Lorem ipsum dolor sit amet.'), 'copyfrom: hydrate from hive key');
     $test->expect($news->author instanceof AuthorModel && !$news->author->dry() && $news->tags instanceof \DB\CortexCollection, 'copyfrom: relations hydrated successful');
     $test->expect($news->get('author', true) == 1, 'get raw data from relational field');
     $news->reset();
     $news->copyfrom('record2', 'title;author');
     $test->expect($news->title = 'Responsive Images' && $news->get('author', true) == 2 && $news->text == NULL, 'copyfrom: limit fields with split-able string');
     $news->reset();
     $news->copyfrom('record2', array('title'));
     $test->expect($news->title = 'Responsive Images' && $news->text == NULL, 'copyfrom: limit fields by array');
     $news->reset();
     $news->copyfrom($dummy, function ($fields) {
         return array_intersect_key($fields, array_flip(array('title')));
     });
     $test->expect($news->title = 'copy test', 'copyfrom: copy from array instead of hive key');
     $test->expect($news->title = 'copy test' && $news->text == NULL, 'copyfrom: limit fields by callback function');
     $all = $news->find();
     $allTitle = $all->getAll('title');
     $test->expect(count($allTitle) == 3 && $allTitle[0] == 'Responsive Images' && $allTitle[1] == 'CSS3 Showcase' && $allTitle[2] == 'Touchable Interfaces', 'collection getAll returns all values of selected field');
     $newsByID = $all->getBy('_id');
     $test->expect(array_keys($newsByID) == array(1, 2, 3), 'collection getBy sorts by given field');
     $newsByAuthorID = $all->getBy('author', true);
     $test->expect(array_keys($newsByAuthorID) == array(2, 1) && count($newsByAuthorID[2]) == 2 && count($newsByAuthorID[1]) == 1, 'collection getBy nested sort by author');
     $allTitle = array();
     foreach ($all as $record) {
         $allTitle[] = $record->title;
     }
     $test->expect(count($allTitle) == 3 && $allTitle[0] == 'Responsive Images' && $allTitle[1] == 'CSS3 Showcase' && $allTitle[2] == 'Touchable Interfaces', 'collection is traversable');
     $news->reset();
     $news->load();
     $r = $news->cast(null, 0);
     $test->expect($r['tags2'] == null && is_int($r['author']), 'simple cast without relations');
     $r = $news->cast(null, 1);
     $test->expect(is_array($r['tags2']) && is_array($r['author']), '1-level nested cast');
     $r = $news->cast(null, 2);
     $test->expect(is_array($r['author']['profile']), '2-level nested cast');
     $r = $news->cast(null, array('*' => 2));
     $test->expect(is_array($r['author']['profile']), '2-level nested cast, alternative');
     $r = $news->cast(null, array('*' => 0, 'author' => 0));
     $test->expect(is_array($r['author']) && $r['tags2'] == null && $r['author']['news'] == null && $r['author']['profile'] == null, 'custom cast');
     $r = $news->cast(null, array('*' => 0, 'author' => array('*' => 1)));
     $test->expect(is_array($r['author']) && $r['tags2'] == null && is_array($r['author']['news']) && is_array($r['author']['profile']), 'custom nested cast');
     $r = $news->cast(null, array('*' => 0, 'author' => array('*' => 0, 'profile' => 0)));
     $test->expect(is_array($r['author']) && $r['tags2'] == null && $r['author']['news'] == null && is_array($r['author']['profile']) && is_int($r['author']['profile']['author']), 'custom nested cast with exclusions');
     $r = $news->cast(null, array('*' => 0, 'author' => array('*' => 0, 'profile' => 1)));
     $test->expect(is_array($r['author']) && $r['tags2'] == null && $r['author']['news'] == null && is_array($r['author']['profile']) && is_array($r['author']['profile']['author']), 'custom multi-level nested cast');
     $filterA = array('foo1 = ? and bar1 = ?', 10, 20);
     $filterB = array('foo2 = ? and bar2 = ?', 30, 40);
     $filterC = array('foo3 = ? and bar3 = ?', 50, 60);
     $filter = $news->mergeFilter(array($filterA, $filterB, $filterC), 'or');
     $test->expect($filter == array('( foo1 = ? and bar1 = ? ) or ( foo2 = ? and bar2 = ? ) or ( foo3 = ? and bar3 = ? )', 10, 20, 30, 40, 50, 60), 'merge multiple filters');
     ///////////////////////////////////
     return $test->results();
 }
Пример #5
0
 function run($db, $type)
 {
     $test = new \Test();
     // clear existing data
     \AuthorModel::setdown();
     \TagModel::setdown();
     \NewsModel::setdown();
     \ProfileModel::setdown();
     // setup models
     \AuthorModel::setup();
     \TagModel::setup();
     \NewsModel::setup();
     \ProfileModel::setup();
     // setup Author
     ///////////////////////////////////
     $author_id = array();
     $author = new \AuthorModel();
     $ac = $author::resolveConfiguration();
     $author_pk = is_int(strpos($type, 'sql')) ? $ac['primary'] : '_id';
     $author->name = 'Johnny English';
     $author->save();
     $author_id[] = $author->_id;
     $author->reset();
     $author->name = 'Ridley Scott';
     $author->save();
     $author_id[] = $author->_id;
     $author->reset();
     $author->name = 'James T. Kirk';
     $author->save();
     $author_id[] = $author->_id;
     $author->reset();
     $allauthors = $author->find()->castAll();
     $allauthors = $this->getResult($allauthors);
     $test->expect(json_encode($allauthors) == '[{"name":"Johnny English"},{"name":"Ridley Scott"},{"name":"James T. Kirk"}]', $type . ': all AuthorModel items created');
     // setup Tags
     ///////////////////////////////////
     $tag_id = array();
     $tag = new \TagModel();
     $tc = $tag::resolveConfiguration();
     $tag_pk = is_int(strpos($type, 'sql')) ? $tc['primary'] : '_id';
     $tag->title = 'Web Design';
     $tag->save();
     $tag_id[] = $tag->_id;
     $tag->reset();
     $tag->title = 'Responsive';
     $tag->save();
     $tag_id[] = $tag->_id;
     $tag->reset();
     $tag->title = 'Usability';
     $tag->save();
     $tag_id[] = $tag->_id;
     $tag->reset();
     $allTags = $this->getResult($tag->find());
     $test->expect(json_encode($allTags) == '[{"title":"Web Design"},{"title":"Responsive"},{"title":"Usability"}]', $type . ': all TagModel items created');
     // setup News
     ///////////////////////////////////
     $news_id = array();
     $news = new \NewsModel();
     $nc = $news::resolveConfiguration();
     $news_pk = is_int(strpos($type, 'sql')) ? $nc['primary'] : '_id';
     $news->title = 'Responsive Images';
     $news->text = 'Lorem Ipsun';
     $news->save();
     $news_id[] = $news->_id;
     $news->reset();
     $news->title = 'CSS3 Showcase';
     $news->text = 'News Text 2';
     $news->save();
     $news_id[] = $news->_id;
     $news->reset();
     $news->title = 'Touchable Interfaces';
     $news->text = 'Lorem Foo';
     $news->save();
     $news_id[] = $news->_id;
     $news->reset();
     $allnews = $this->getResult($news->find(null, array('order' => 'title')));
     $test->expect(count($allnews) == 3 && $allnews[0]['title'] == 'CSS3 Showcase' && $allnews[1]['title'] == 'Responsive Images' && $allnews[2]['title'] == 'Touchable Interfaces', $type . ': all NewsModel items created');
     // belongs-to author relation
     ///////////////////////////////////
     $author->load();
     $news->load(array($news_pk . ' = ?', $news_id[0]));
     $news->author = $author;
     $news->save();
     $news->reset();
     $news->load(array($news_pk . ' = ?', $news_id[0]));
     $test->expect($news->author->name == 'Johnny English', $type . ': belongs-to-one: author relation created');
     $news->author = NULL;
     $news->save();
     $news->reset();
     $news->load(array($news_pk . ' = ?', $news_id[0]));
     $test->expect(empty($news->author), $type . ': belongs-to-one: author relation released');
     $news->author = $author->_id;
     $news->save();
     $news->reset();
     $news->load(array($news_pk . ' = ?', $news_id[0]));
     $test->expect($news->author->name == 'Johnny English', $type . ': belongs-to-one: relation created by raw id');
     // belongs-to-many tag relation
     ///////////////////////////////////
     $tag1 = new \TagModel();
     $tag1->load(array($tag_pk . ' = ?', $tag_id[0]));
     $tag2 = new \TagModel();
     $tag2->load(array($tag_pk . ' = ?', $tag_id[1]));
     $news->tags = array($tag1, $tag2);
     $news->save();
     $news->reset();
     $news->load(array($news_pk . ' = ?', $news_id[0]));
     $test->expect($news->tags[0]->title == 'Web Design' && $news->tags[1]->title == 'Responsive', $type . ': belongs-to-many: relations created with array of mapper objects');
     $news->reset();
     $news->load(array($news_pk . ' = ?', $news_id[1]));
     $news->tags = array($tag_id[1], $tag_id[2]);
     $news->save();
     $news->reset();
     $news->load(array($news_pk . ' = ?', $news_id[1]));
     $test->expect(count($news->tags) == 2 && $news->tags[0]->title == 'Responsive' && $news->tags[1]->title == 'Usability', $type . ': belongs-to-many: relations created with array of IDs');
     $news->tags = null;
     $news->save();
     $news->reset();
     $news->load(array($news_pk . ' = ?', $news_id[1]));
     $test->expect(empty($news->tags), $type . ': belongs-to-many: relations released');
     $tag->reset();
     $news->load(array($news_pk . ' = ?', $news_id[1]));
     $news->tags = $tag->load(array($tag_pk . ' != ?', $tag_id[0]));
     $news->save();
     $news->reset();
     $news->load(array($news_pk . ' = ?', $news_id[1]));
     $test->expect($news->tags[0]->title == 'Responsive' && $news->tags[1]->title == 'Usability', $type . ': belongs-to-many: relations created with hydrated mapper');
     $news->reset();
     $tag->reset();
     $news->load(array($news_pk . ' = ?', $news_id[2]));
     $news->tags = $tag_id[0] . ';' . $tag_id[2];
     $news->save();
     $news->reset();
     $news->load(array($news_pk . ' = ?', $news_id[2]));
     $test->expect($news->tags[0]->title == 'Web Design' && $news->tags[1]->title == 'Usability', $type . ': belongs-to-many: relations created with split-able string');
     $test->expect(is_object($news->tags) && $news->tags instanceof \DB\CortexCollection, $type . ': belongs-to-many: result is collection');
     // has-one relation
     ///////////////////////////////////
     $profile = new ProfileModel();
     $pc = $profile::resolveConfiguration();
     $profile_pk = is_int(strpos($type, 'sql')) ? $pc['primary'] : '_id';
     $profile->message = 'Hello World';
     $profile->author = $author->load(array($author_pk . ' = ?', $author_id[0]));
     $profile->save();
     $profile_id = $profile->_id;
     $profile->reset();
     $author->reset();
     $author->load(array($author_pk . ' = ?', $author_id[0]));
     $profile->load(array($profile_pk . ' = ?', $profile_id));
     $test->expect($author->profile->message == 'Hello World' && $profile->author->name == "Johnny English", $type . ': has-one: relation assigned');
     $profile->reset();
     $profile->message = 'I\'m feeling lucky';
     $profile->image = 'lolcat.jpg';
     $author->reset();
     $author->load(array($author_pk . ' = ?', $author_id[1]));
     $author->profile = $profile;
     $author->save();
     $profile->reset();
     $author->reset();
     $author->load(array($author_pk . ' = ?', $author_id[1]));
     $test->expect($author->profile->message == 'I\'m feeling lucky', $type . ': has-one: inverse relation');
     // has-many relation
     ///////////////////////////////////
     $author->load(array($author_pk . ' = ?', $author_id[0]));
     $result = $this->getResult($author->news);
     $test->expect($result[0]['title'] == "Responsive Images" && $result[0]['tags'][0]['title'] == 'Web Design' && $result[0]['tags'][1]['title'] == 'Responsive', $type . ': has-many inverse relation');
     // many to many relation
     ///////////////////////////////////
     $news->load(array($news_pk . ' = ?', $news_id[0]));
     $news->tags2 = array($tag_id[0], $tag_id[1]);
     $news->save();
     $news->reset();
     $news->load(array($news_pk . ' = ?', $news_id[0]));
     $test->expect($news->tags2[0]['title'] == 'Web Design' && $news->tags2[1]['title'] == 'Responsive', $type . ': many-to-many relation created');
     $test->expect(is_object($news->tags2) && $news->tags2 instanceof \DB\CortexCollection, $type . ': many-to-many: result is collection');
     $tag3 = $tag->load(array($tag_pk . ' = ?', $tag_id[2]));
     $news->tags2[] = $tag3;
     $news->save();
     $a = count($news->tags2);
     $news->reset();
     $news->load(array($news_pk . ' = ?', $news_id[0]));
     $test->expect(count($news->tags2) == 3 && $a == 3, $type . ': many-to-many relation added implicitly');
     $news->load(array($news_pk . ' = ?', $news_id[0]));
     $news->tags2 = NULL;
     $news->save();
     $news->reset();
     $news->load(array($news_pk . ' = ?', $news_id[0]));
     $test->expect(is_null($news->tags2), $type . ': many-to-many relation released');
     $news->reset();
     $news->title = 'Can it run Crysis?';
     $news->text = 'XOXO';
     $news->tags2 = array($tag_id[0]);
     $news->save();
     $news_id[] = $news->_id;
     $news->reset();
     $news->load(array($news_pk . ' = ?', $news_id[3]));
     $a = count($news->tags2);
     $tag1 = $tag->find(array($tag_pk . ' = ?', $tag_id[0]));
     $b = count($tag1[0]->news);
     $c = $tag1[0]->news[0]->title == 'Can it run Crysis?';
     $news->erase();
     $tag1 = $tag->find(array($tag_pk . ' = ?', $tag_id[0]));
     $d = count($tag1[0]->news);
     $test->expect($a == 1 && $b == 1 && $c && $d == 0, $type . ': many-to-many relation cleaned by erase cascade');
     $news->load(array($news_pk . ' = ?', $news_id[0]));
     $all = $news->find();
     $test->expect($all[1]->tags2 === NULL && $all[2]->author === NULL, $type . ': empty relations are NULL');
     $arr = $news->cast();
     $test->expect(is_array($arr['tags']), $type . ': collection becomes array in casted model');
     if ($type == 'mongo') {
         $test->expect(is_string($arr['_id']), $type . ': id becomes string in casted model');
     }
     ///////////////////////////////////
     return $test->results();
 }
Пример #6
0
 function run($db, $type)
 {
     $test = new \Test();
     // setup
     ///////////////////////////////////
     $author = new \AuthorModel();
     $news = new \NewsModel();
     $profile = new \ProfileModel();
     $tag = new \TagModel();
     $ac = $author::resolveConfiguration();
     $author_pk = is_int(strpos($type, 'sql')) ? $ac['primary'] : '_id';
     $nc = $news::resolveConfiguration();
     $news_pk = is_int(strpos($type, 'sql')) ? $nc['primary'] : '_id';
     $tc = $tag::resolveConfiguration();
     $tag_pk = is_int(strpos($type, 'sql')) ? $tc['primary'] : '_id';
     $authorIDs = $author->find()->getAll('_id');
     $all = $news->find();
     $newsIDs = $all->getAll('_id');
     $profileIDs = $profile->find()->getAll('_id');
     $tagIDs = $tag->find()->getAll('_id');
     // add another relation
     $news->load(array('title = ?', 'CSS3 Showcase'));
     $news->author = $author->load(array($author_pk . ' = ?', $authorIDs[0]));
     $news->save();
     $news->reset();
     $author->reset();
     // has-filter on belongs-to relation
     ///////////////////////////////////
     $result = $author->has('news', array('title like ?', '%Image%'))->afind();
     $test->expect(count($result) == 1 && $result[0]['name'] == 'Johnny English', $type . ': has filter on many-to-one field');
     $test->expect(count($result[0]['news']) == 2 && $result[0]['news'][0]['title'] == 'Responsive Images' && $result[0]['news'][1]['title'] == 'CSS3 Showcase', $type . ': has filter does not prune relation set');
     $result = $news->has('author', array('name = ?', 'Johnny English'))->afind();
     $test->expect(count($result) == 2 && $result[0]['title'] == 'Responsive Images' && $result[1]['title'] == 'CSS3 Showcase', $type . ': has filter on one-to-many field');
     // add another profile
     $profile->message = 'Beam me up, Scotty!';
     $profile->author = $authorIDs[2];
     $profile->save();
     $profile->reset();
     $result = $author->has('profile', array('message LIKE ?', '%Scotty%'))->afind();
     $test->expect(count($result) == 1 && $result[0]['name'] == 'James T. Kirk' && $result[0]['profile']['message'] == 'Beam me up, Scotty!', $type . ': has filter on one-to-one field');
     $result = $profile->has('author', array('name LIKE ?', '%Kirk%'))->afind();
     $test->expect(count($result) == 1 && $result[0]['message'] == 'Beam me up, Scotty!' && $result[0]['author']['name'] == 'James T. Kirk', $type . ': has filter on one-to-one field, inverse');
     // add mm tags
     $news->load(array('title = ?', 'Responsive Images'));
     $news->tags2 = array($tagIDs[0], $tagIDs[1]);
     $news->save();
     $news->load(array('title = ?', 'CSS3 Showcase'));
     $news->tags2 = array($tagIDs[1], $tagIDs[2]);
     $news->save();
     $news->reset();
     $result = $news->has('tags2', array('title like ?', '%Design%'))->find();
     $test->expect(count($result) == 1 && $result[0]['title'] == 'Responsive Images', $type . ': has filter on many-to-many field');
     $result = $news->has('tags2', array('title = ?', 'Responsive'))->find();
     $test->expect(count($result) == 2 && $result[0]['title'] == 'Responsive Images' && $result[1]['title'] == 'CSS3 Showcase', $type . ': has filter on many-to-many field, additional test');
     $result = $tag->has('news', array('title = ?', 'Responsive Images'))->find();
     $test->expect(count($result) == 2 && $result[0]['title'] == 'Web Design' && $result[1]['title'] == 'Responsive', $type . ': has filter on many-to-many field, inverse');
     // add another tag
     $news->load(array('title = ?', 'Touchable Interfaces'));
     $news->tags2 = array($tagIDs[1]);
     $news->save();
     $news->reset();
     $tag->has('news', array('text LIKE ? and title LIKE ?', '%Lorem%', '%Interface%'));
     $result = $tag->find();
     $test->expect(count($result) == 1 && $result[0]['title'] == 'Responsive', $type . ': has filter with multiple conditions');
     $news->has('tags2', array('title = ? OR title = ?', 'Usability', 'Web Design'));
     $result = $news->afind(array('text = ?', 'Lorem Ipsun'));
     $test->expect(count($result) == 1 && $result[0]['title'] == 'Responsive Images', $type . ': find with condition and has filter');
     $news->load(array('title = ?', 'Responsive Images'));
     $news->author = $authorIDs[1];
     $news->save();
     $news->reset();
     $news->has('tags2', array('title = ? OR title = ?', 'Usability', 'Web Design'));
     $news->has('author', array('name = ?', 'Ridley Scott'));
     $result = $news->afind();
     $test->expect(count($result) == 1 && $result[0]['title'] == 'Responsive Images', $type . ': find with multiple has filters on different relations');
     // add another news to author 2
     $news->load(array($news_pk . ' = ?', $newsIDs[2]));
     $news->author = $authorIDs[1];
     $news->save();
     $news->reset();
     $news->has('author', array('name = ?', 'Ridley Scott'));
     $news->load();
     $res = array();
     while (!$news->dry()) {
         $res[] = $news->title;
         $news->next();
     }
     $test->expect(count($res) == 2 && $res[0] == 'Responsive Images' && $res[1] == 'Touchable Interfaces', $type . ': has filter in load context');
     $news->reset();
     $news->fields(array('title'));
     $news->load();
     $test->expect(!empty($news->title) && empty($news->author) && empty($news->text) && empty($news->tags) && empty($news->tags2), $type . ': use a whitelist to restrict fields');
     unset($news);
     $news = new \NewsModel();
     $news->fields(array('title', 'tags', 'tags2', 'author'), true);
     $news->load();
     $test->expect(empty($news->title) && empty($news->author) && !empty($news->text) && empty($news->tags) && empty($news->tags2), $type . ': use a blacklist to restrict fields');
     unset($news);
     $news = new \NewsModel();
     $news->fields(array('tags.title'));
     $news->load();
     $test->expect(!empty($news->tags[0]->title) && empty($news->tags[0]->news), $type . ': set restricted fields to related mappers');
     $news->filter('tags2', null, array('order' => 'title ASC'));
     $news->load(array('title = ?', 'Responsive Images'));
     $test->expect($news->tags2[0]->title == 'Responsive' && $news->tags2[1]->title == 'Web Design', $type . ': filter with sorting of related records');
     // get all tags sorted by their usage in news articles
     $tag->reset();
     $tag->countRel('news');
     $result = $tag->find(null, array('order' => 'count_news DESC, title'))->castAll(0);
     $test->expect($result[0]['title'] == 'Responsive' && $result[0]['count_news'] == 3 && $result[1]['title'] == 'Usability' && $result[1]['count_news'] == 1 && $result[2]['title'] == 'Web Design' && $result[2]['count_news'] == 1, $type . ': count and sort on many-to-many relation');
     // get all authors sorted by the amount of news they have written
     $author->reset();
     $author->countRel('news');
     $result = $author->find(null, array('order' => 'count_news DESC'))->castAll(0);
     $test->expect($result[0]['name'] == 'Ridley Scott' && $result[0]['count_news'] == 2 && $result[1]['name'] == 'Johnny English' && $result[1]['count_news'] == 1 && $result[2]['name'] == 'James T. Kirk' && $result[2]['count_news'] == null, $type . ': count and sort on one-to-many relation');
     $tag->reset();
     $tag->countRel('news');
     $result = $tag->find(null, array('order' => 'count_news DESC, title DESC', 'limit' => 1, 'offset' => 1))->castAll(0);
     $test->expect($result[0]['title'] == 'Web Design' && $result[0]['count_news'] == 1, $type . ': apply limit and offset on aggregated collection');
     $author->reset();
     $author->countRel('news');
     $author->has('news', array('text like ?', '%Lorem%'));
     $result = $author->find()->castAll(0);
     $test->expect(count($result) == 1 && $result[0]['name'] == 'Ridley Scott' && $result[0]['count_news'] == 2, $type . ': has-filter and 1:M relation counter');
     $author->reset();
     $id = $author->load()->next()->_id;
     $tag->reset();
     $tag->countRel('news');
     $tag->has('news', array('author = ?', $id));
     $result = $tag->find(null, array('order' => 'count_news desc'))->castAll(0);
     $test->expect(count($result) == 2 && $result[0]['title'] == 'Responsive' && $result[0]['count_news'] == 3 && $result[1]['title'] == 'Web Design' && $result[1]['count_news'] == 1, $type . ': has-filter and M:M relation counter');
     ///////////////////////////////////
     return $test->results();
 }