DocumentTest.php 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913
  1. <?php
  2. /**
  3. * Lithium: the most rad php framework
  4. *
  5. * @copyright Copyright 2013, Union of RAD (http://union-of-rad.org)
  6. * @license http://opensource.org/licenses/bsd-license.php The BSD License
  7. */
  8. namespace lithium\tests\cases\data\entity;
  9. use MongoId;
  10. use MongoDate;
  11. use lithium\data\source\MongoDb;
  12. use lithium\data\entity\Document;
  13. use lithium\data\collection\DocumentSet;
  14. use lithium\data\source\mongo_db\Schema;
  15. use lithium\tests\mocks\data\model\MockDocumentPost;
  16. use lithium\tests\mocks\data\model\MockDocumentMultipleKey;
  17. use lithium\tests\mocks\data\source\MockMongoConnection;
  18. use lithium\tests\mocks\data\model\MockDocumentSource;
  19. class DocumentTest extends \lithium\test\Unit {
  20. protected $_model = 'lithium\tests\mocks\data\model\MockDocumentPost';
  21. public function setUp() {
  22. MockDocumentPost::$connection = new MongoDb(array('autoConnect' => false));
  23. MockDocumentPost::$connection->connection = new MockMongoConnection();
  24. MockDocumentMultipleKey::$connection = new MockDocumentSource();
  25. }
  26. public function testFindAllAndIterate() {
  27. $set = MockDocumentPost::all();
  28. $expected = array('_id' => 1, 'name' => 'One', 'content' => 'Lorem ipsum one');
  29. $result = $set->current()->data();
  30. $this->assertEqual($expected, $result);
  31. $expected = array('_id' => 2, 'name' => 'Two', 'content' => 'Lorem ipsum two');
  32. $result = $set->next()->data();
  33. $this->assertEqual($expected, $result);
  34. $expected = array('_id' => 3, 'name' => 'Three', 'content' => 'Lorem ipsum three');
  35. $set->next();
  36. $result = $set->current()->data();
  37. $this->assertEqual($expected, $result);
  38. $result = $set->next();
  39. $this->assertTrue(empty($result));
  40. $expected = array('_id' => 1, 'name' => 'One', 'content' => 'Lorem ipsum one');
  41. $result = $set->rewind()->data();
  42. $this->assertEqual($expected, $result);
  43. }
  44. public function testFindOne() {
  45. $document = MockDocumentPost::find('first');
  46. $expected = array('_id' => 2, 'name' => 'Two', 'content' => 'Lorem ipsum two');
  47. $result = $document->data();
  48. $this->assertEqual($expected, $result);
  49. }
  50. public function testGetFields() {
  51. $document = MockDocumentPost::find('first');
  52. $expected = 2;
  53. $result = $document->_id;
  54. $this->assertEqual($expected, $result);
  55. $expected = 'Two';
  56. $result = $document->name;
  57. $this->assertEqual($expected, $result);
  58. $expected = 'Lorem ipsum two';
  59. $result = $document->content;
  60. $this->assertEqual($expected, $result);
  61. }
  62. public function testSetField() {
  63. $doc = new Document();
  64. $doc->_id = 4;
  65. $doc->name = 'Four';
  66. $doc->content = 'Lorem ipsum four';
  67. $expected = array(
  68. '_id' => 4,
  69. 'name' => 'Four',
  70. 'content' => 'Lorem ipsum four'
  71. );
  72. $result = $doc->data();
  73. $this->assertEqual($expected, $result);
  74. }
  75. public function testSyncModified() {
  76. $doc = new Document();
  77. $doc->_id = 4;
  78. $doc->name = 'Four';
  79. $doc->content = 'Lorem ipsum four';
  80. $expected = array(
  81. '_id' => true,
  82. 'name' => true,
  83. 'content' => true
  84. );
  85. $this->assertEqual($expected, $doc->modified());
  86. $doc->sync();
  87. $this->assertEqual(array_fill_keys(array_keys($expected), false), $doc->modified());
  88. $doc->_id = 5;
  89. $doc->content = null;
  90. $doc->new = null;
  91. $expected = array(
  92. '_id' => true,
  93. 'name' => false,
  94. 'content' => true,
  95. 'new' => true
  96. );
  97. $this->assertEqual($expected, $doc->modified());
  98. $doc = new Document(array('model' => $this->_model));
  99. $doc->id = 4;
  100. $doc->name = 'Four';
  101. $doc->content = 'Lorem ipsum four';
  102. $doc->array = array(1, 2, 3, 4);
  103. $doc->subdoc = array(
  104. 'setting' => 'something',
  105. 'foo' => 'bar',
  106. 'sub' => array('name' => 'A sub sub doc')
  107. );
  108. $doc->subdocs = array(
  109. array('id' => 1),
  110. array('id' => 2),
  111. array('id' => 3),
  112. array('id' => 4)
  113. );
  114. $fields = array('id', 'name', 'content', 'array', 'subdoc', 'subdocs');
  115. $expected = array_fill_keys($fields, true);
  116. $this->assertEqual($expected, $doc->modified());
  117. $doc->sync();
  118. $this->assertEqual(array_fill_keys($fields, false), $doc->modified());
  119. $doc->id = 5;
  120. $doc->content = null;
  121. $doc->new = null;
  122. $doc->subdoc->foo = 'baz';
  123. $doc->array[] = 5;
  124. $doc->subdocs[] = array('id' => 5);
  125. $expected['name'] = false;
  126. $expected['new'] = true;
  127. $fields[] = 'new';
  128. $this->assertEqual($expected, $doc->modified());
  129. $doc->sync();
  130. $expected = array_fill_keys($fields, false);
  131. $this->assertEqual($expected, $doc->modified());
  132. $doc->sync();
  133. $doc->subdocs[1]->updated = true;
  134. $expected['subdocs'] = true;
  135. $this->assertEqual($expected, $doc->modified());
  136. $doc->sync();
  137. $doc->array[1] = array('foo' => 'bar');
  138. $expected['array'] = true;
  139. $this->assertEqual($expected, $doc->modified());
  140. $doc->sync();
  141. }
  142. public function testSetAndCoerceArray() {
  143. $schema = new Schema(array('fields' => array(
  144. 'forceArray' => array('type' => 'string', 'array' => true),
  145. 'array' => array('type' => 'string', 'array' => true),
  146. 'dictionary' => array('type' => 'string', 'array' => true),
  147. 'numbers' => array('type' => 'integer', 'array' => true),
  148. 'objects' => array('type' => 'object', 'array' => true),
  149. 'deeply' => array('type' => 'object', 'array' => true),
  150. 'foo' => array('type' => 'string')
  151. )));
  152. $exists = true;
  153. $doc = new Document(compact('schema', 'exists'));
  154. $doc->array = array(1, 2, 3);
  155. $doc->forceArray = 'foo';
  156. $result = $doc->export();
  157. $this->assertTrue($result['update']['forceArray'] instanceof DocumentSet);
  158. $this->assertTrue($result['update']['array'] instanceof DocumentSet);
  159. $this->assertIdentical(array('foo'), $result['update']['forceArray']->data());
  160. $doc->forceArray = false;
  161. $result = $doc->export();
  162. $this->assertIdentical(array(false), $result['update']['forceArray']->data());
  163. $doc->forceArray = array();
  164. $result = $doc->export();
  165. $this->assertIdentical(array(), $result['update']['forceArray']->data());
  166. }
  167. public function testNestedKeyGetSet() {
  168. $doc = new Document(array('model' => $this->_model, 'data' => array(
  169. 'name' => 'Bob', 'location' => 'New York, NY', 'profile' => array(
  170. 'occupation' => 'Developer', 'likes' => 'PHP', 'dislikes' => 'Java'
  171. )
  172. )));
  173. $expected = array('occupation' => 'Developer', 'likes' => 'PHP', 'dislikes' => 'Java');
  174. $this->assertEqual($expected, $doc->profile->data());
  175. $this->assertEqual('Java', $doc->profile->dislikes);
  176. $this->assertEqual('Java', $doc->{'profile.dislikes'});
  177. $this->assertNull($doc->{'profile.'});
  178. $this->assertNull($doc->{'profile.foo'});
  179. $this->assertNull($doc->{'profile.foo.bar'});
  180. $doc->{'profile.dislikes'} = 'Crystal Reports';
  181. $this->assertEqual('Crystal Reports', $doc->profile->dislikes);
  182. $doc->{'profile.foo.bar'} = 'baz';
  183. $this->assertTrue($doc->profile->foo instanceof Document);
  184. $this->assertEqual(array('bar' => 'baz'), $doc->profile->foo->data());
  185. $post = new Document(array('model' => $this->_model, 'data' => array(
  186. 'title' => 'Blog Post',
  187. 'body' => 'Some post content.',
  188. 'meta' => array('tags' => array('foo', 'bar', 'baz'))
  189. )));
  190. $this->assertEqual(array('foo', 'bar', 'baz'), $post->meta->tags->data());
  191. $post->{'meta.tags'}[] = 'dib';
  192. $this->assertEqual(array('foo', 'bar', 'baz', 'dib'), $post->meta->tags->data());
  193. }
  194. public function testNoItems() {
  195. $doc = new Document(array('model' => $this->_model, 'data' => array()));
  196. $result = $doc->_id;
  197. $this->assertFalse($result);
  198. }
  199. public function testWithData() {
  200. $doc = new DocumentSet(array('model' => $this->_model, 'data' => array(
  201. array('_id' => 1, 'name' => 'One', 'content' => 'Lorem ipsum one'),
  202. array('_id' => 2, 'name' => 'Two', 'content' => 'Lorem ipsum two'),
  203. array('_id' => 3, 'name' => 'Three', 'content' => 'Lorem ipsum three')
  204. )));
  205. $expected = array('_id' => 1, 'name' => 'One', 'content' => 'Lorem ipsum one');
  206. $result = $doc->current()->data();
  207. $this->assertEqual($expected, $result);
  208. $expected = array('_id' => 2, 'name' => 'Two', 'content' => 'Lorem ipsum two');
  209. $result = $doc->next()->data();
  210. $this->assertEqual($expected, $result);
  211. }
  212. public function testExplicitSet() {
  213. $doc = new Document();
  214. $doc->set(array('_id' => 4));
  215. $doc->set(array('name' => 'Four'));
  216. $doc->set(array('content' => 'Lorem ipsum four'));
  217. $expected = array('_id' => 4, 'name' => 'Four', 'content' => 'Lorem ipsum four');
  218. $result = $doc->data();
  219. $this->assertEqual($expected, $result);
  220. }
  221. public function testSetMultiple() {
  222. $doc = new DocumentSet(array('model' => $this->_model));
  223. $doc->set(array(
  224. array('_id' => 1, 'name' => 'One', 'content' => 'Lorem ipsum one'),
  225. array('_id' => 2, 'name' => 'Two', 'content' => 'Lorem ipsum two'),
  226. array('_id' => 3, 'name' => 'Three', 'content' => 'Lorem ipsum three')
  227. ));
  228. $expected = array('_id' => 1, 'name' => 'One', 'content' => 'Lorem ipsum one');
  229. return;
  230. $result = $doc->current()->data();
  231. $this->assertEqual($expected, $result);
  232. $expected = array('_id' => 2, 'name' => 'Two', 'content' => 'Lorem ipsum two');
  233. $result = $doc->next()->data();
  234. $this->assertEqual($expected, $result);
  235. }
  236. public function testSetMultipleNested() {
  237. $doc = new Document(array('model' => $this->_model));
  238. $doc->_id = 123;
  239. $doc->type = 'father';
  240. $doc->set(array('children' => array(
  241. array('_id' => 124, 'type' => 'child', 'children' => null),
  242. array('_id' => 125, 'type' => 'child', 'children' => null)
  243. )));
  244. $this->assertEqual('father', $doc->type);
  245. $this->assertTrue($doc->children instanceof DocumentSet);
  246. $expected = array('_id' => 124, 'type' => 'child', 'children' => null);
  247. $result = $doc->children[124]->data();
  248. $this->assertEqual($expected, $result);
  249. $expected = array('_id' => 125, 'type' => 'child', 'children' => null);
  250. $result = $doc->children[125]->data();
  251. // @todo Make $result = $doc->children->{1}->data(); work as well (and ...->{'1'}->...)
  252. $this->assertEqual($expected, $result);
  253. }
  254. public function testSetNested() {
  255. $doc = new Document(array('model' => $this->_model));
  256. $doc->_id = 123;
  257. $doc->name = 'father';
  258. $doc->set(array('child' => array('_id' => 124, 'name' => 'child')));
  259. $this->assertEqual('father', $doc->name);
  260. $this->assertTrue(is_object($doc->child), 'children is not an object');
  261. $this->assertTrue($doc->child instanceof Document, 'Child is not of the type Document');
  262. $this->skipIf(!$doc->child instanceof Document, 'Child is not of the type Document');
  263. $expected = 124;
  264. $result = $doc->child->_id;
  265. $this->assertEqual($expected, $result);
  266. $expected = 'child';
  267. $result = $doc->child->name;
  268. $this->assertEqual($expected, $result);
  269. }
  270. public function testNestedSingle() {
  271. $doc = new Document(array('model' => $this->_model));
  272. $doc->arr1 = array('something' => 'else');
  273. $doc->arr2 = array('some' => 'noses', 'have' => 'it');
  274. $this->assertTrue($doc->arr1 instanceof Document);
  275. $this->assertTrue($doc->arr2 instanceof Document);
  276. }
  277. public function testRewindNoData() {
  278. $doc = new DocumentSet();
  279. $result = $doc->rewind();
  280. $this->assertFalse($result);
  281. }
  282. public function testRewindData() {
  283. $doc = new DocumentSet(array('model' => $this->_model, 'data' => array(
  284. array('_id' => 1, 'name' => 'One'),
  285. array('_id' => 2, 'name' => 'Two'),
  286. array('_id' => 3, 'name' => 'Three')
  287. )));
  288. $expected = array('_id' => 1, 'name' => 'One');
  289. $result = $doc->rewind()->data();
  290. $this->assertEqual($expected, $result);
  291. }
  292. public function testUpdateWithSingleKey() {
  293. $doc = new Document(array('model' => $this->_model));
  294. $result = MockDocumentPost::meta('key');
  295. $this->assertEqual('_id', $result);
  296. $doc->_id = 3;
  297. $this->assertFalse($doc->exists());
  298. $doc->sync(12);
  299. $this->assertTrue($doc->exists());
  300. $this->assertEqual(12, $doc->_id);
  301. }
  302. public function testUpdateWithMultipleKeys() {
  303. $model = 'lithium\tests\mocks\data\model\MockDocumentMultipleKey';
  304. $model::config(array('meta' => array('key' => array('_id', 'rev'), 'foo' => true)));
  305. $doc = new Document(compact('model'));
  306. $result = $model::meta('key');
  307. $this->assertEqual(array('_id', 'rev'), $result);
  308. $doc->_id = 3;
  309. $this->assertFalse($doc->exists());
  310. $doc->sync(array(12, '1-2'));
  311. $this->assertTrue($doc->exists());
  312. $this->assertEqual(12, $doc->_id);
  313. $this->assertEqual('1-2', $doc->rev);
  314. }
  315. public function testArrayValueNestedDocument() {
  316. $doc = new Document(array(
  317. 'model' => 'lithium\tests\mocks\data\model\MockDocumentPost',
  318. 'data' => array(
  319. '_id' => 12, 'arr' => array('_id' => 33, 'name' => 'stone'), 'name' => 'bird'
  320. )
  321. ));
  322. $this->assertEqual(12, $doc->_id);
  323. $this->assertEqual('bird', $doc->name);
  324. $this->assertTrue(is_object($doc->arr), 'arr is not an object');
  325. $this->assertTrue($doc->arr instanceof Document, 'arr is not of the type Document');
  326. $this->skipIf(!$doc->arr instanceof Document, 'arr is not of the type Document');
  327. $this->assertEqual(33, $doc->arr->_id);
  328. $this->assertEqual('stone', $doc->arr->name);
  329. }
  330. public function testArrayValueGet() {
  331. $doc = new Document(array(
  332. 'model' => $this->_model,
  333. 'data' => array('_id' => 12, 'name' => 'Joe', 'sons' => array('Moe', 'Greg'))
  334. ));
  335. $this->assertEqual(12, $doc->_id);
  336. $this->assertEqual('Joe', $doc->name);
  337. $this->assertTrue($doc->sons instanceof DocumentSet, 'arr is not an array');
  338. $this->assertEqual(array('Moe', 'Greg'), $doc->sons->data());
  339. }
  340. public function testArrayValueSet() {
  341. $doc = new Document(array('model' => $this->_model));
  342. $doc->_id = 12;
  343. $doc->name = 'Joe';
  344. $doc->sons = array('Moe', 'Greg', 12, 0.3);
  345. $doc->set(array('daughters' => array('Susan', 'Tinkerbell')));
  346. $expected = array(
  347. '_id' => 12,
  348. 'name' => 'Joe',
  349. 'sons' => array('Moe', 'Greg', 12, 0.3),
  350. 'daughters' => array('Susan', 'Tinkerbell')
  351. );
  352. $result = $doc->data();
  353. $this->assertEqual($expected, $result);
  354. }
  355. public function testInvalidCall() {
  356. $doc = new Document();
  357. $this->expectException("No model bound to call `medicin`.");
  358. $result = $doc->medicin();
  359. $this->assertNull($result);
  360. }
  361. public function testCall() {
  362. $doc = new Document(array('model' => 'lithium\tests\mocks\data\model\MockDocumentPost'));
  363. $expected = 'lithium';
  364. $result = $doc->medicin();
  365. $this->assertEqual($expected, $result);
  366. $result = $doc->ret();
  367. $this->assertNull($result);
  368. $expected = 'nose';
  369. $result = $doc->ret('nose');
  370. $this->assertEqual($expected, $result);
  371. $expected = 'job';
  372. $result = $doc->ret('nose','job');
  373. $this->assertEqual($expected, $result);
  374. }
  375. public function testEmptyValues() {
  376. $doc = new Document(array(
  377. 'model' => 'lithium\tests\mocks\data\model\MockDocumentPost',
  378. 'data' => array(
  379. 'title' => 'Post',
  380. 'content' => 'Lorem Ipsum',
  381. 'parsed' => null,
  382. 'permanent' => false
  383. )
  384. ));
  385. $expected = array(
  386. 'title' => 'Post',
  387. 'content' => 'Lorem Ipsum',
  388. 'parsed' => null,
  389. 'permanent' => false
  390. );
  391. $result = $doc->data();
  392. $this->assertEqual($expected, $result);
  393. }
  394. public function testBooleanValues() {
  395. $doc = new Document(array('model' => $this->_model));
  396. $doc->tall = false;
  397. $doc->fat = true;
  398. $doc->set(array('hair' => true, 'fast' => false));
  399. $expected = array('fast', 'fat', 'hair', 'tall');
  400. $result = array_keys($doc->data());
  401. sort($result);
  402. $this->assertEqual($expected, $result);
  403. }
  404. public function testIsset() {
  405. $doc = new Document(array('data' => array(
  406. 'title' => 'Post',
  407. 'content' => 'Lorem Ipsum'
  408. )));
  409. $this->assertTrue(isset($doc->title));
  410. $this->assertTrue(isset($doc->content));
  411. $this->assertFalse(isset($doc->body));
  412. }
  413. public function testData() {
  414. $doc = new Document(array(
  415. 'data' => array(
  416. 'title' => 'Post',
  417. 'content' => 'Lorem Ipsum',
  418. 'parsed' => null,
  419. 'permanent' => false
  420. )
  421. ));
  422. $expected = array(
  423. 'title' => 'Post',
  424. 'content' => 'Lorem Ipsum',
  425. 'parsed' => null,
  426. 'permanent' => false
  427. );
  428. $result = $doc->data();
  429. $this->assertEqual($expected, $result);
  430. $expected = 'Post';
  431. $result = $doc->data('title');
  432. $this->assertEqual($expected, $result);
  433. $result = $doc->data('permanent');
  434. $this->assertFalse($result);
  435. $doc = new Document();
  436. $this->assertNull($doc->data('field'));
  437. }
  438. public function testUnset() {
  439. $doc = new Document(array(
  440. 'data' => array(
  441. 'title' => 'Post',
  442. 'content' => 'Lorem Ipsum',
  443. 'parsed' => null,
  444. 'permanent' => false
  445. )
  446. ));
  447. $expected = array(
  448. 'title' => 'Post',
  449. 'content' => 'Lorem Ipsum',
  450. 'parsed' => null,
  451. 'permanent' => false
  452. );
  453. $result = $doc->data();
  454. $this->assertEqual($expected, $result);
  455. unset($expected['title']);
  456. unset($doc->title);
  457. $this->assertEqual($expected, $doc->data());
  458. unset($expected['parsed']);
  459. unset($doc->parsed);
  460. $result = $doc->data();
  461. $this->assertEqual($expected, $result);
  462. unset($expected['permanent']);
  463. unset($doc->permanent);
  464. $result = $doc->data();
  465. $this->assertEqual($expected, $result);
  466. unset($doc->none);
  467. }
  468. public function testUnsetNested() {
  469. $data = array(
  470. 'a' => 1,
  471. 'b' => array(
  472. 'ba' => 21,
  473. 'bb' => 22
  474. ),
  475. 'c' => array(
  476. 'ca' => 31,
  477. 'cb' => array(
  478. 'cba' => 321,
  479. 'cbb' => 322
  480. )
  481. ),
  482. 'd' => array(
  483. 'da' => 41
  484. )
  485. );
  486. $model = $this->_model;
  487. $doc = new Document(compact('model', 'data'));
  488. $expected = $data;
  489. $result = $doc->data();
  490. $this->assertEqual($expected, $result);
  491. unset($doc->c->cb->cba);
  492. unset($expected['c']['cb']['cba']);
  493. $result = $doc->data();
  494. $this->assertEqual($expected, $result);
  495. unset($doc->b->bb);
  496. unset($expected['b']['bb']);
  497. $result = $doc->data();
  498. $this->assertEqual($expected, $result);
  499. unset($doc->a);
  500. unset($expected['a']);
  501. $result = $doc->data();
  502. $this->assertEqual($expected, $result);
  503. unset($doc->d);
  504. unset($expected['d']);
  505. $result = $doc->data();
  506. $this->assertEqual($expected, $result);
  507. $exportedRoot = $doc->export();
  508. $this->assertEqual(array('a' => true, 'd' => true), $exportedRoot['remove']);
  509. $exportedB = $doc->b->export();
  510. $this->assertEqual(array('bb' => true), $exportedB['remove']);
  511. $exportedCCB = $doc->c->cb->export();
  512. $this->assertEqual(array('cba' => true), $exportedCCB['remove']);
  513. }
  514. public function testErrors() {
  515. $doc = new Document(array('data' => array(
  516. 'title' => 'Post',
  517. 'content' => 'Lorem Ipsum',
  518. 'parsed' => null,
  519. 'permanent' => false
  520. )));
  521. $errors = array('title' => 'Too short', 'parsed' => 'Empty');
  522. $doc->errors($errors);
  523. $expected = $errors;
  524. $result = $doc->errors();
  525. $this->assertEqual($expected, $result);
  526. $expected = 'Too short';
  527. $result = $doc->errors('title');
  528. $this->assertEqual($expected, $result);
  529. $doc->errors('title', 'Too generic');
  530. $expected = 'Too generic';
  531. $result = $doc->errors('title');
  532. $this->assertEqual($expected, $result);
  533. }
  534. public function testDocumentNesting() {
  535. $model = $this->_model;
  536. $data = array('top' => 'level', 'second' => array('level' => 'of data'));
  537. $doc = new Document(compact('model', 'data'));
  538. $this->assertTrue(isset($doc->top));
  539. $this->assertTrue(isset($doc->second->level));
  540. $this->assertTrue($doc->second instanceof Document);
  541. $this->assertEqual('level', $doc->top);
  542. $this->assertEqual('of data', $doc->second->level);
  543. }
  544. public function testPropertyIteration() {
  545. $doc = new Document(array('data' => array('foo' => 'bar', 'baz' => 'dib')));
  546. $keys = array(null, 'foo', 'baz');
  547. $values = array(null, 'bar', 'dib');
  548. foreach ($doc as $key => $value) {
  549. $this->assertEqual(next($keys), $key);
  550. $this->assertEqual(next($values), $value);
  551. }
  552. reset($keys);
  553. reset($values);
  554. foreach ($doc as $key => $value) {
  555. $this->assertEqual(next($keys), $key);
  556. $this->assertEqual(next($values), $value);
  557. }
  558. }
  559. public function testExport() {
  560. $data = array('foo' => 'bar', 'baz' => 'dib');
  561. $doc = new Document(compact('data') + array('exists' => false));
  562. $expected = array(
  563. 'data' => array('foo' => 'bar', 'baz' => 'dib'),
  564. 'update' => array('foo' => 'bar', 'baz' => 'dib'),
  565. 'remove' => array(),
  566. 'increment' => array(),
  567. 'key' => '',
  568. 'exists' => false
  569. );
  570. $this->assertEqual($expected, $doc->export());
  571. }
  572. /**
  573. * Tests that documents nested within existing documents also exist, and vice versa.
  574. */
  575. public function testNestedObjectExistence() {
  576. $model = $this->_model;
  577. $data = array('foo' => array('bar' => 'bar', 'baz' => 'dib'));
  578. $doc = new Document(compact('model', 'data') + array('exists' => false));
  579. $this->assertFalse($doc->exists());
  580. $this->assertFalse($doc->foo->exists());
  581. $doc = new Document(compact('model', 'data') + array('exists' => true));
  582. $this->assertTrue($doc->exists());
  583. $this->assertTrue($doc->foo->exists());
  584. $doc = new Document(compact('model', 'data') + array('exists' => true));
  585. $subDoc = new Document(array('data' => array('bar' => 'stuff')));
  586. $this->assertTrue($doc->foo->exists());
  587. $this->assertFalse($subDoc->exists());
  588. $doc->foo = $subDoc;
  589. $this->assertTrue($doc->exists());
  590. $this->assertFalse($doc->foo->exists());
  591. $doc->sync();
  592. $this->assertTrue($doc->foo->exists());
  593. }
  594. /**
  595. * Tests that a modified `Document` exports the proper fields in a newly-appended nested
  596. * `Document`.
  597. */
  598. public function testModifiedExport() {
  599. $model = $this->_model;
  600. $data = array('foo' => 'bar', 'baz' => 'dib');
  601. $doc = new Document(compact('model', 'data') + array('exists' => false));
  602. $doc->nested = array('more' => 'data');
  603. $newData = $doc->export();
  604. $expected = array('foo' => 'bar', 'baz' => 'dib', 'nested.more' => 'data');
  605. $this->assertFalse($newData['exists']);
  606. $this->assertEqual(array('foo' => 'bar', 'baz' => 'dib'), $newData['data']);
  607. $this->assertEqual(3, count($newData['update']));
  608. $this->assertTrue($newData['update']['nested'] instanceof Document);
  609. $result = $newData['update']['nested']->export();
  610. $this->assertFalse($result['exists']);
  611. $this->assertEqual(array('more' => 'data'), $result['data']);
  612. $this->assertEqual(array('more' => 'data'), $result['update']);
  613. $this->assertEqual('nested', $result['key']);
  614. $doc = new Document(compact('model') + array('exists' => true, 'data' => array(
  615. 'foo' => 'bar', 'baz' => 'dib'
  616. )));
  617. $result = $doc->export();
  618. $this->assertEqual($result['data'], $result['update']);
  619. $doc->nested = array('more' => 'data');
  620. $this->assertEqual('data', $doc->nested->more);
  621. $modified = $doc->export();
  622. $this->assertTrue($modified['exists']);
  623. $this->assertEqual(array('foo' => 'bar', 'baz' => 'dib'), $modified['data']);
  624. $this->assertEqual(array('foo', 'baz', 'nested'), array_keys($modified['update']));
  625. $this->assertNull($modified['key']);
  626. $nested = $modified['update']['nested']->export();
  627. $this->assertFalse($nested['exists']);
  628. $this->assertEqual(array('more' => 'data'), $nested['data']);
  629. $this->assertEqual('nested', $nested['key']);
  630. $doc->sync();
  631. $result = $doc->export();
  632. $this->assertEqual($result['data'], $result['update']);
  633. $doc->more = 'cowbell';
  634. $doc->nested->evenMore = 'cowbell';
  635. $modified = $doc->export();
  636. $expected = array('more' => 'cowbell') + $modified['data'];
  637. $this->assertEqual($expected, $modified['update']);
  638. $this->assertEqual(array('foo', 'baz', 'nested'), array_keys($modified['data']));
  639. $this->assertEqual('bar', $modified['data']['foo']);
  640. $this->assertEqual('dib', $modified['data']['baz']);
  641. $this->assertTrue($modified['exists']);
  642. $nested = $modified['data']['nested']->export();
  643. $this->assertTrue($nested['exists']);
  644. $this->assertEqual(array('more' => 'data'), $nested['data']);
  645. $this->assertEqual(array('evenMore' => 'cowbell') + $nested['data'], $nested['update']);
  646. $this->assertEqual('nested', $nested['key']);
  647. $doc->sync();
  648. $doc->nested->evenMore = 'foo!';
  649. $modified = $doc->export();
  650. $this->assertEqual($modified['data'], $modified['update']);
  651. $nested = $modified['data']['nested']->export();
  652. $this->assertEqual(array('evenMore' => 'foo!') + $nested['data'], $nested['update']);
  653. }
  654. public function testArrayConversion() {
  655. $this->skipIf(!MongoDb::enabled(), "MongoDB not enabled, skipping conversion tests.");
  656. $time = time();
  657. $doc = new Document(array('data' => array(
  658. '_id' => new MongoId(),
  659. 'date' => new MongoDate($time)
  660. )));
  661. $result = $doc->data();
  662. $this->assertPattern('/^[a-f0-9]{24}$/', $result['_id']);
  663. $this->assertEqual($time, $result['date']);
  664. }
  665. public function testArrayInterface() {
  666. $doc = new Document();
  667. $doc->field = 'value';
  668. $this->assertEqual('value', $doc['field']);
  669. $doc['field'] = 'newvalue';
  670. $this->assertEqual('newvalue', $doc->field);
  671. unset($doc['field']);
  672. $this->assertNull($doc->field);
  673. }
  674. /**
  675. * Tests that unassigned fields with default schema values are auto-populated at access time.
  676. */
  677. public function testSchemaValueInitialization() {
  678. $doc = new Document(array('schema' => new Schema(array('fields' => array(
  679. 'foo' => array('type' => 'string', 'default' => 'bar')
  680. )))));
  681. $this->assertFalse($doc->data());
  682. $this->assertEqual('bar', $doc->foo);
  683. $this->assertEqual(array('foo' => 'bar'), $doc->data());
  684. }
  685. public function testInitializationWithNestedFields() {
  686. $doc = new Document(array('model' => $this->_model, 'data' => array(
  687. 'simple' => 'value',
  688. 'nested.foo' => 'first',
  689. 'nested.bar' => 'second',
  690. 'really.nested.key' => 'value'
  691. )));
  692. $this->assertEqual('value', $doc->simple);
  693. $this->assertEqual('first', $doc->nested->foo);
  694. $this->assertEqual('second', $doc->nested->bar);
  695. $this->assertEqual('value', $doc->really->nested->key);
  696. $result = array_keys($doc->data());
  697. sort($result);
  698. $this->assertEqual(array('nested', 'really', 'simple'), $result);
  699. }
  700. public function testWithArraySchemaReusedName() {
  701. $model = $this->_model;
  702. $schema = new Schema(array('fields' => array(
  703. '_id' => array('type' => 'id'),
  704. 'bar' => array('array' => true),
  705. 'foo' => array('type' => 'object', 'array' => true),
  706. 'foo.foo' => array('type' => 'integer'),
  707. 'foo.bar' => array('type' => 'integer')
  708. )));
  709. $doc = new Document(compact('model', 'schema'));
  710. $doc->foo[] = array('foo' => 1, 'bar' => 100);
  711. $expected = array('foo' => array(array('foo' => 1, 'bar' => 100)));
  712. $this->assertEqual($expected, $doc->data());
  713. }
  714. public function testIdGetDoesNotSet() {
  715. $document = MockDocumentPost::create();
  716. $message = 'The `_id` key should not be set.';
  717. $this->assertFalse(array_key_exists('_id', $document->data()), $message);
  718. $document->_id === "";
  719. $this->assertFalse(array_key_exists('_id', $document->data()), $message);
  720. }
  721. /**
  722. * Ensures that the data returned from the `data()` method matches the
  723. * internal state of the object.
  724. */
  725. public function testEnsureArrayExportFidelity() {
  726. $data = array(
  727. 'department_3' => 0,
  728. 4 => 0,
  729. 5 => 0,
  730. 6 => 0,
  731. '6x' => 0,
  732. 7 => 0,
  733. 8 => 0,
  734. 10 => 0,
  735. 12 => 0
  736. );
  737. $doc = new Document(compact('data'));
  738. $this->assertIdentical($data, $doc->data());
  739. }
  740. }
  741. ?>