PageRenderTime 72ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/tests/model/VersionedOwnershipTest.php

http://github.com/silverstripe/sapphire
PHP | 809 lines | 549 code | 102 blank | 158 comment | 2 complexity | 2bf9dd1e707554a8ff510b1184774650 MD5 | raw file
Possible License(s): BSD-3-Clause, MIT, CC-BY-3.0, GPL-2.0, AGPL-1.0, LGPL-2.1
  1. <?php
  2. use SilverStripe\ORM\Versioning\Versioned;
  3. use SilverStripe\ORM\DataObject;
  4. use SilverStripe\ORM\FieldType\DBDatetime;
  5. /**
  6. * Tests ownership API of versioned DataObjects
  7. */
  8. class VersionedOwnershipTest extends SapphireTest {
  9. protected $extraDataObjects = array(
  10. 'VersionedOwnershipTest_Object',
  11. 'VersionedOwnershipTest_Subclass',
  12. 'VersionedOwnershipTest_Related',
  13. 'VersionedOwnershipTest_Attachment',
  14. 'VersionedOwnershipTest_RelatedMany',
  15. 'VersionedOwnershipTest_Page',
  16. 'VersionedOwnershipTest_Banner',
  17. 'VersionedOwnershipTest_Image',
  18. 'VersionedOwnershipTest_CustomRelation',
  19. );
  20. protected static $fixture_file = 'VersionedOwnershipTest.yml';
  21. public function setUp() {
  22. parent::setUp();
  23. Versioned::set_stage(Versioned::DRAFT);
  24. // Automatically publish any object named *_published
  25. foreach($this->getFixtureFactory()->getFixtures() as $class => $fixtures) {
  26. foreach($fixtures as $name => $id) {
  27. if(stripos($name, '_published') !== false) {
  28. /** @var Versioned|DataObject $object */
  29. $object = DataObject::get($class)->byID($id);
  30. $object->copyVersionToStage(Versioned::DRAFT, Versioned::LIVE);
  31. }
  32. }
  33. }
  34. }
  35. /**
  36. * Virtual "sleep" that doesn't actually slow execution, only advances DBDateTime::now()
  37. *
  38. * @param int $minutes
  39. */
  40. protected function sleep($minutes) {
  41. $now = DBDatetime::now();
  42. $date = DateTime::createFromFormat('Y-m-d H:i:s', $now->getValue());
  43. $date->modify("+{$minutes} minutes");
  44. DBDatetime::set_mock_now($date->format('Y-m-d H:i:s'));
  45. }
  46. /**
  47. * Test basic findOwned() in stage mode
  48. */
  49. public function testFindOwned() {
  50. /** @var VersionedOwnershipTest_Subclass $subclass1 */
  51. $subclass1 = $this->objFromFixture('VersionedOwnershipTest_Subclass', 'subclass1_published');
  52. $this->assertDOSEquals(
  53. [
  54. ['Title' => 'Related 1'],
  55. ['Title' => 'Attachment 1'],
  56. ['Title' => 'Attachment 2'],
  57. ['Title' => 'Attachment 5'],
  58. ['Title' => 'Related Many 1'],
  59. ['Title' => 'Related Many 2'],
  60. ['Title' => 'Related Many 3'],
  61. ],
  62. $subclass1->findOwned()
  63. );
  64. // Non-recursive search
  65. $this->assertDOSEquals(
  66. [
  67. ['Title' => 'Related 1'],
  68. ['Title' => 'Related Many 1'],
  69. ['Title' => 'Related Many 2'],
  70. ['Title' => 'Related Many 3'],
  71. ],
  72. $subclass1->findOwned(false)
  73. );
  74. /** @var VersionedOwnershipTest_Subclass $subclass2 */
  75. $subclass2 = $this->objFromFixture('VersionedOwnershipTest_Subclass', 'subclass2_published');
  76. $this->assertDOSEquals(
  77. [
  78. ['Title' => 'Related 2'],
  79. ['Title' => 'Attachment 3'],
  80. ['Title' => 'Attachment 4'],
  81. ['Title' => 'Attachment 5'],
  82. ['Title' => 'Related Many 4'],
  83. ],
  84. $subclass2->findOwned()
  85. );
  86. // Non-recursive search
  87. $this->assertDOSEquals(
  88. [
  89. ['Title' => 'Related 2'],
  90. ['Title' => 'Related Many 4'],
  91. ],
  92. $subclass2->findOwned(false)
  93. );
  94. /** @var VersionedOwnershipTest_Related $related1 */
  95. $related1 = $this->objFromFixture('VersionedOwnershipTest_Related', 'related1');
  96. $this->assertDOSEquals(
  97. [
  98. ['Title' => 'Attachment 1'],
  99. ['Title' => 'Attachment 2'],
  100. ['Title' => 'Attachment 5'],
  101. ],
  102. $related1->findOwned()
  103. );
  104. /** @var VersionedOwnershipTest_Related $related2 */
  105. $related2 = $this->objFromFixture('VersionedOwnershipTest_Related', 'related2_published');
  106. $this->assertDOSEquals(
  107. [
  108. ['Title' => 'Attachment 3'],
  109. ['Title' => 'Attachment 4'],
  110. ['Title' => 'Attachment 5'],
  111. ],
  112. $related2->findOwned()
  113. );
  114. }
  115. /**
  116. * Test findOwners
  117. */
  118. public function testFindOwners() {
  119. /** @var VersionedOwnershipTest_Attachment $attachment1 */
  120. $attachment1 = $this->objFromFixture('VersionedOwnershipTest_Attachment', 'attachment1');
  121. $this->assertDOSEquals(
  122. [
  123. ['Title' => 'Related 1'],
  124. ['Title' => 'Subclass 1'],
  125. ],
  126. $attachment1->findOwners()
  127. );
  128. // Non-recursive search
  129. $this->assertDOSEquals(
  130. [
  131. ['Title' => 'Related 1'],
  132. ],
  133. $attachment1->findOwners(false)
  134. );
  135. /** @var VersionedOwnershipTest_Attachment $attachment5 */
  136. $attachment5 = $this->objFromFixture('VersionedOwnershipTest_Attachment', 'attachment5_published');
  137. $this->assertDOSEquals(
  138. [
  139. ['Title' => 'Related 1'],
  140. ['Title' => 'Related 2'],
  141. ['Title' => 'Subclass 1'],
  142. ['Title' => 'Subclass 2'],
  143. ],
  144. $attachment5->findOwners()
  145. );
  146. // Non-recursive
  147. $this->assertDOSEquals(
  148. [
  149. ['Title' => 'Related 1'],
  150. ['Title' => 'Related 2'],
  151. ],
  152. $attachment5->findOwners(false)
  153. );
  154. /** @var VersionedOwnershipTest_Related $related1 */
  155. $related1 = $this->objFromFixture('VersionedOwnershipTest_Related', 'related1');
  156. $this->assertDOSEquals(
  157. [
  158. ['Title' => 'Subclass 1'],
  159. ],
  160. $related1->findOwners()
  161. );
  162. }
  163. /**
  164. * Test findOwners on Live stage
  165. */
  166. public function testFindOwnersLive() {
  167. // Modify a few records on stage
  168. $related2 = $this->objFromFixture('VersionedOwnershipTest_Related', 'related2_published');
  169. $related2->Title .= ' Modified';
  170. $related2->write();
  171. $attachment3 = $this->objFromFixture('VersionedOwnershipTest_Attachment', 'attachment3_published');
  172. $attachment3->Title .= ' Modified';
  173. $attachment3->write();
  174. $attachment4 = $this->objFromFixture('VersionedOwnershipTest_Attachment', 'attachment4_published');
  175. $attachment4->delete();
  176. $subclass2ID = $this->idFromFixture('VersionedOwnershipTest_Subclass', 'subclass2_published');
  177. // Check that stage record is ok
  178. /** @var VersionedOwnershipTest_Subclass $subclass2Stage */
  179. $subclass2Stage = Versioned::get_by_stage('VersionedOwnershipTest_Subclass', 'Stage')->byID($subclass2ID);
  180. $this->assertDOSEquals(
  181. [
  182. ['Title' => 'Related 2 Modified'],
  183. ['Title' => 'Attachment 3 Modified'],
  184. ['Title' => 'Attachment 5'],
  185. ['Title' => 'Related Many 4'],
  186. ],
  187. $subclass2Stage->findOwned()
  188. );
  189. // Non-recursive
  190. $this->assertDOSEquals(
  191. [
  192. ['Title' => 'Related 2 Modified'],
  193. ['Title' => 'Related Many 4'],
  194. ],
  195. $subclass2Stage->findOwned(false)
  196. );
  197. // Live records are unchanged
  198. /** @var VersionedOwnershipTest_Subclass $subclass2Live */
  199. $subclass2Live = Versioned::get_by_stage('VersionedOwnershipTest_Subclass', 'Live')->byID($subclass2ID);
  200. $this->assertDOSEquals(
  201. [
  202. ['Title' => 'Related 2'],
  203. ['Title' => 'Attachment 3'],
  204. ['Title' => 'Attachment 4'],
  205. ['Title' => 'Attachment 5'],
  206. ['Title' => 'Related Many 4'],
  207. ],
  208. $subclass2Live->findOwned()
  209. );
  210. // Test non-recursive
  211. $this->assertDOSEquals(
  212. [
  213. ['Title' => 'Related 2'],
  214. ['Title' => 'Related Many 4'],
  215. ],
  216. $subclass2Live->findOwned(false)
  217. );
  218. }
  219. /**
  220. * Test that objects are correctly published recursively
  221. */
  222. public function testRecursivePublish() {
  223. /** @var VersionedOwnershipTest_Subclass $parent */
  224. $parent = $this->objFromFixture('VersionedOwnershipTest_Subclass', 'subclass1_published');
  225. $parentID = $parent->ID;
  226. $banner1 = $this->objFromFixture('VersionedOwnershipTest_RelatedMany', 'relatedmany1_published');
  227. $banner2 = $this->objFromFixture('VersionedOwnershipTest_RelatedMany', 'relatedmany2_published');
  228. $banner2ID = $banner2->ID;
  229. // Modify, Add, and Delete banners on stage
  230. $banner1->Title = 'Renamed Banner 1';
  231. $banner1->write();
  232. $banner2->delete();
  233. $banner4 = new VersionedOwnershipTest_RelatedMany();
  234. $banner4->Title = 'New Banner';
  235. $parent->Banners()->add($banner4);
  236. // Check state of objects before publish
  237. $oldLiveBanners = [
  238. ['Title' => 'Related Many 1'],
  239. ['Title' => 'Related Many 2'], // Will be deleted
  240. // `Related Many 3` isn't published
  241. ];
  242. $newBanners = [
  243. ['Title' => 'Renamed Banner 1'], // Renamed
  244. ['Title' => 'Related Many 3'], // Published without changes
  245. ['Title' => 'New Banner'], // Created
  246. ];
  247. $parentDraft = Versioned::get_by_stage('VersionedOwnershipTest_Subclass', Versioned::DRAFT)
  248. ->byID($parentID);
  249. $this->assertDOSEquals($newBanners, $parentDraft->Banners());
  250. $parentLive = Versioned::get_by_stage('VersionedOwnershipTest_Subclass', Versioned::LIVE)
  251. ->byID($parentID);
  252. $this->assertDOSEquals($oldLiveBanners, $parentLive->Banners());
  253. // On publishing of owner, all children should now be updated
  254. $parent->publishRecursive();
  255. // Now check each object has the correct state
  256. $parentDraft = Versioned::get_by_stage('VersionedOwnershipTest_Subclass', Versioned::DRAFT)
  257. ->byID($parentID);
  258. $this->assertDOSEquals($newBanners, $parentDraft->Banners());
  259. $parentLive = Versioned::get_by_stage('VersionedOwnershipTest_Subclass', Versioned::LIVE)
  260. ->byID($parentID);
  261. $this->assertDOSEquals($newBanners, $parentLive->Banners());
  262. // Check that the deleted banner hasn't actually been deleted from the live stage,
  263. // but in fact has been unlinked.
  264. $banner2Live = Versioned::get_by_stage('VersionedOwnershipTest_RelatedMany', Versioned::LIVE)
  265. ->byID($banner2ID);
  266. $this->assertEmpty($banner2Live->PageID);
  267. }
  268. /**
  269. * Test that owning objects get unpublished as needed
  270. */
  271. public function testRecursiveUnpublish() {
  272. // Unsaved objects can't be unpublished
  273. $unsaved = new VersionedOwnershipTest_Subclass();
  274. $this->assertFalse($unsaved->doUnpublish());
  275. // Draft-only objects can't be unpublished
  276. /** @var VersionedOwnershipTest_RelatedMany $banner3Unpublished */
  277. $banner3Unpublished = $this->objFromFixture('VersionedOwnershipTest_RelatedMany', 'relatedmany3');
  278. $this->assertFalse($banner3Unpublished->doUnpublish());
  279. // First test: mid-level unpublish; We expect that owners should be unpublished, but not
  280. // owned objects, nor other siblings shared by the same owner.
  281. $related2 = $this->objFromFixture('VersionedOwnershipTest_Related', 'related2_published');
  282. /** @var VersionedOwnershipTest_Attachment $attachment3 */
  283. $attachment3 = $this->objFromFixture('VersionedOwnershipTest_Attachment', 'attachment3_published');
  284. /** @var VersionedOwnershipTest_RelatedMany $relatedMany4 */
  285. $relatedMany4 = $this->objFromFixture('VersionedOwnershipTest_RelatedMany', 'relatedmany4_published');
  286. /** @var VersionedOwnershipTest_Related $related2 */
  287. $this->assertTrue($related2->doUnpublish());
  288. $subclass2 = $this->objFromFixture('VersionedOwnershipTest_Subclass', 'subclass2_published');
  289. /** @var VersionedOwnershipTest_Subclass $subclass2 */
  290. $this->assertFalse($subclass2->isPublished()); // Owner IS unpublished
  291. $this->assertTrue($attachment3->isPublished()); // Owned object is NOT unpublished
  292. $this->assertTrue($relatedMany4->isPublished()); // Owned object by owner is NOT unpublished
  293. // Second test: multi-level unpublish should recursively cascade down all owning objects
  294. // Publish related2 again
  295. $subclass2->publishRecursive();
  296. $this->assertTrue($subclass2->isPublished());
  297. $this->assertTrue($related2->isPublished());
  298. $this->assertTrue($attachment3->isPublished());
  299. // Unpublish leaf node
  300. $this->assertTrue($attachment3->doUnpublish());
  301. // Now all owning objects (only) are unpublished
  302. $this->assertFalse($attachment3->isPublished()); // Unpublished because we just unpublished it
  303. $this->assertFalse($related2->isPublished()); // Unpublished because it owns attachment3
  304. $this->assertFalse($subclass2->isPublished()); // Unpublished ecause it owns related2
  305. $this->assertTrue($relatedMany4->isPublished()); // Stays live because recursion only affects owners not owned.
  306. }
  307. public function testRecursiveArchive() {
  308. // When archiving an object, any published owners should be unpublished at the same time
  309. // but NOT achived
  310. /** @var VersionedOwnershipTest_Attachment $attachment3 */
  311. $attachment3 = $this->objFromFixture('VersionedOwnershipTest_Attachment', 'attachment3_published');
  312. $attachment3ID = $attachment3->ID;
  313. $this->assertTrue($attachment3->doArchive());
  314. // This object is on neither stage nor live
  315. $stageAttachment = Versioned::get_by_stage('VersionedOwnershipTest_Attachment', Versioned::DRAFT)
  316. ->byID($attachment3ID);
  317. $liveAttachment = Versioned::get_by_stage('VersionedOwnershipTest_Attachment', Versioned::LIVE)
  318. ->byID($attachment3ID);
  319. $this->assertEmpty($stageAttachment);
  320. $this->assertEmpty($liveAttachment);
  321. // Owning object is unpublished only
  322. /** @var VersionedOwnershipTest_Related $stageOwner */
  323. $stageOwner = $this->objFromFixture('VersionedOwnershipTest_Related', 'related2_published');
  324. $this->assertTrue($stageOwner->isOnDraft());
  325. $this->assertFalse($stageOwner->isPublished());
  326. // Bottom level owning object is also unpublished
  327. /** @var VersionedOwnershipTest_Subclass $stageTopOwner */
  328. $stageTopOwner = $this->objFromFixture('VersionedOwnershipTest_Subclass', 'subclass2_published');
  329. $this->assertTrue($stageTopOwner->isOnDraft());
  330. $this->assertFalse($stageTopOwner->isPublished());
  331. }
  332. public function testRecursiveRevertToLive() {
  333. /** @var VersionedOwnershipTest_Subclass $parent */
  334. $parent = $this->objFromFixture('VersionedOwnershipTest_Subclass', 'subclass1_published');
  335. $parentID = $parent->ID;
  336. $banner1 = $this->objFromFixture('VersionedOwnershipTest_RelatedMany', 'relatedmany1_published');
  337. $banner2 = $this->objFromFixture('VersionedOwnershipTest_RelatedMany', 'relatedmany2_published');
  338. $banner2ID = $banner2->ID;
  339. // Modify, Add, and Delete banners on stage
  340. $banner1->Title = 'Renamed Banner 1';
  341. $banner1->write();
  342. $banner2->delete();
  343. $banner4 = new VersionedOwnershipTest_RelatedMany();
  344. $banner4->Title = 'New Banner';
  345. $banner4->write();
  346. $parent->Banners()->add($banner4);
  347. // Check state of objects before publish
  348. $liveBanners = [
  349. ['Title' => 'Related Many 1'],
  350. ['Title' => 'Related Many 2'],
  351. ];
  352. $modifiedBanners = [
  353. ['Title' => 'Renamed Banner 1'], // Renamed
  354. ['Title' => 'Related Many 3'], // Published without changes
  355. ['Title' => 'New Banner'], // Created
  356. ];
  357. $parentDraft = Versioned::get_by_stage('VersionedOwnershipTest_Subclass', Versioned::DRAFT)
  358. ->byID($parentID);
  359. $this->assertDOSEquals($modifiedBanners, $parentDraft->Banners());
  360. $parentLive = Versioned::get_by_stage('VersionedOwnershipTest_Subclass', Versioned::LIVE)
  361. ->byID($parentID);
  362. $this->assertDOSEquals($liveBanners, $parentLive->Banners());
  363. // When reverting parent, all records should be put back on stage
  364. $this->assertTrue($parent->doRevertToLive());
  365. // Now check each object has the correct state
  366. $parentDraft = Versioned::get_by_stage('VersionedOwnershipTest_Subclass', Versioned::DRAFT)
  367. ->byID($parentID);
  368. $this->assertDOSEquals($liveBanners, $parentDraft->Banners());
  369. $parentLive = Versioned::get_by_stage('VersionedOwnershipTest_Subclass', Versioned::LIVE)
  370. ->byID($parentID);
  371. $this->assertDOSEquals($liveBanners, $parentLive->Banners());
  372. // Check that the newly created banner, even though it still exist, has been
  373. // unlinked from the reverted draft record
  374. /** @var VersionedOwnershipTest_RelatedMany $banner4Draft */
  375. $banner4Draft = Versioned::get_by_stage('VersionedOwnershipTest_RelatedMany', Versioned::DRAFT)
  376. ->byID($banner4->ID);
  377. $this->assertTrue($banner4Draft->isOnDraft());
  378. $this->assertFalse($banner4Draft->isPublished());
  379. $this->assertEmpty($banner4Draft->PageID);
  380. }
  381. /**
  382. * Test that rolling back to a single version works recursively
  383. */
  384. public function testRecursiveRollback() {
  385. /** @var VersionedOwnershipTest_Subclass $subclass2 */
  386. $this->sleep(1);
  387. $subclass2 = $this->objFromFixture('VersionedOwnershipTest_Subclass', 'subclass2_published');
  388. // Create a few new versions
  389. $versions = [];
  390. for($version = 1; $version <= 3; $version++) {
  391. // Write owned objects
  392. $this->sleep(1);
  393. foreach($subclass2->findOwned(true) as $obj) {
  394. $obj->Title .= " - v{$version}";
  395. $obj->write();
  396. }
  397. // Write parent
  398. $this->sleep(1);
  399. $subclass2->Title .= " - v{$version}";
  400. $subclass2->write();
  401. $versions[$version] = $subclass2->Version;
  402. }
  403. // Check reverting to first version
  404. $this->sleep(1);
  405. $subclass2->doRollbackTo($versions[1]);
  406. /** @var VersionedOwnershipTest_Subclass $subclass2Draft */
  407. $subclass2Draft = Versioned::get_by_stage('VersionedOwnershipTest_Subclass', Versioned::DRAFT)
  408. ->byID($subclass2->ID);
  409. $this->assertEquals('Subclass 2 - v1', $subclass2Draft->Title);
  410. $this->assertDOSEquals(
  411. [
  412. ['Title' => 'Related 2 - v1'],
  413. ['Title' => 'Attachment 3 - v1'],
  414. ['Title' => 'Attachment 4 - v1'],
  415. ['Title' => 'Attachment 5 - v1'],
  416. ['Title' => 'Related Many 4 - v1'],
  417. ],
  418. $subclass2Draft->findOwned(true)
  419. );
  420. // Check rolling forward to a later version
  421. $this->sleep(1);
  422. $subclass2->doRollbackTo($versions[3]);
  423. /** @var VersionedOwnershipTest_Subclass $subclass2Draft */
  424. $subclass2Draft = Versioned::get_by_stage('VersionedOwnershipTest_Subclass', Versioned::DRAFT)
  425. ->byID($subclass2->ID);
  426. $this->assertEquals('Subclass 2 - v1 - v2 - v3', $subclass2Draft->Title);
  427. $this->assertDOSEquals(
  428. [
  429. ['Title' => 'Related 2 - v1 - v2 - v3'],
  430. ['Title' => 'Attachment 3 - v1 - v2 - v3'],
  431. ['Title' => 'Attachment 4 - v1 - v2 - v3'],
  432. ['Title' => 'Attachment 5 - v1 - v2 - v3'],
  433. ['Title' => 'Related Many 4 - v1 - v2 - v3'],
  434. ],
  435. $subclass2Draft->findOwned(true)
  436. );
  437. // And rolling back one version
  438. $this->sleep(1);
  439. $subclass2->doRollbackTo($versions[2]);
  440. /** @var VersionedOwnershipTest_Subclass $subclass2Draft */
  441. $subclass2Draft = Versioned::get_by_stage('VersionedOwnershipTest_Subclass', Versioned::DRAFT)
  442. ->byID($subclass2->ID);
  443. $this->assertEquals('Subclass 2 - v1 - v2', $subclass2Draft->Title);
  444. $this->assertDOSEquals(
  445. [
  446. ['Title' => 'Related 2 - v1 - v2'],
  447. ['Title' => 'Attachment 3 - v1 - v2'],
  448. ['Title' => 'Attachment 4 - v1 - v2'],
  449. ['Title' => 'Attachment 5 - v1 - v2'],
  450. ['Title' => 'Related Many 4 - v1 - v2'],
  451. ],
  452. $subclass2Draft->findOwned(true)
  453. );
  454. }
  455. /**
  456. * Test that you can find owners without owned_by being defined explicitly
  457. */
  458. public function testInferedOwners() {
  459. // Make sure findOwned() works
  460. /** @var VersionedOwnershipTest_Page $page1 */
  461. $page1 = $this->objFromFixture('VersionedOwnershipTest_Page', 'page1_published');
  462. /** @var VersionedOwnershipTest_Page $page2 */
  463. $page2 = $this->objFromFixture('VersionedOwnershipTest_Page', 'page2_published');
  464. $this->assertDOSEquals(
  465. [
  466. ['Title' => 'Banner 1'],
  467. ['Title' => 'Image 1'],
  468. ['Title' => 'Custom 1'],
  469. ],
  470. $page1->findOwned()
  471. );
  472. $this->assertDOSEquals(
  473. [
  474. ['Title' => 'Banner 2'],
  475. ['Title' => 'Banner 3'],
  476. ['Title' => 'Image 1'],
  477. ['Title' => 'Image 2'],
  478. ['Title' => 'Custom 2'],
  479. ],
  480. $page2->findOwned()
  481. );
  482. // Check that findOwners works
  483. /** @var VersionedOwnershipTest_Image $image1 */
  484. $image1 = $this->objFromFixture('VersionedOwnershipTest_Image', 'image1_published');
  485. /** @var VersionedOwnershipTest_Image $image2 */
  486. $image2 = $this->objFromFixture('VersionedOwnershipTest_Image', 'image2_published');
  487. $this->assertDOSEquals(
  488. [
  489. ['Title' => 'Banner 1'],
  490. ['Title' => 'Banner 2'],
  491. ['Title' => 'Page 1'],
  492. ['Title' => 'Page 2'],
  493. ],
  494. $image1->findOwners()
  495. );
  496. $this->assertDOSEquals(
  497. [
  498. ['Title' => 'Banner 1'],
  499. ['Title' => 'Banner 2'],
  500. ],
  501. $image1->findOwners(false)
  502. );
  503. $this->assertDOSEquals(
  504. [
  505. ['Title' => 'Banner 3'],
  506. ['Title' => 'Page 2'],
  507. ],
  508. $image2->findOwners()
  509. );
  510. $this->assertDOSEquals(
  511. [
  512. ['Title' => 'Banner 3'],
  513. ],
  514. $image2->findOwners(false)
  515. );
  516. // Test custom relation can findOwners()
  517. /** @var VersionedOwnershipTest_CustomRelation $custom1 */
  518. $custom1 = $this->objFromFixture('VersionedOwnershipTest_CustomRelation', 'custom1_published');
  519. $this->assertDOSEquals(
  520. [['Title' => 'Page 1']],
  521. $custom1->findOwners()
  522. );
  523. }
  524. }
  525. /**
  526. * @mixin Versioned
  527. */
  528. class VersionedOwnershipTest_Object extends DataObject implements TestOnly {
  529. private static $extensions = array(
  530. 'SilverStripe\\ORM\\Versioning\\Versioned',
  531. );
  532. private static $db = array(
  533. 'Title' => 'Varchar(255)',
  534. 'Content' => 'Text',
  535. );
  536. }
  537. /**
  538. * Object which:
  539. * - owns a has_one object
  540. * - owns has_many objects
  541. */
  542. class VersionedOwnershipTest_Subclass extends VersionedOwnershipTest_Object implements TestOnly {
  543. private static $db = array(
  544. 'Description' => 'Text',
  545. );
  546. private static $has_one = array(
  547. 'Related' => 'VersionedOwnershipTest_Related',
  548. );
  549. private static $has_many = array(
  550. 'Banners' => 'VersionedOwnershipTest_RelatedMany'
  551. );
  552. private static $owns = array(
  553. 'Related',
  554. 'Banners',
  555. );
  556. }
  557. /**
  558. * Object which:
  559. * - owned by has_many objects
  560. * - owns many_many Objects
  561. *
  562. * @mixin Versioned
  563. */
  564. class VersionedOwnershipTest_Related extends DataObject implements TestOnly {
  565. private static $extensions = array(
  566. 'SilverStripe\\ORM\\Versioning\\Versioned',
  567. );
  568. private static $db = array(
  569. 'Title' => 'Varchar(255)',
  570. );
  571. private static $has_many = array(
  572. 'Parents' => 'VersionedOwnershipTest_Subclass.Related',
  573. );
  574. private static $owned_by = array(
  575. 'Parents',
  576. );
  577. private static $many_many = array(
  578. // Note : Currently unversioned, take care
  579. 'Attachments' => 'VersionedOwnershipTest_Attachment',
  580. );
  581. private static $owns = array(
  582. 'Attachments',
  583. );
  584. }
  585. /**
  586. * Object which is owned by a has_one object
  587. *
  588. * @mixin Versioned
  589. */
  590. class VersionedOwnershipTest_RelatedMany extends DataObject implements TestOnly {
  591. private static $extensions = array(
  592. 'SilverStripe\\ORM\\Versioning\\Versioned',
  593. );
  594. private static $db = array(
  595. 'Title' => 'Varchar(255)',
  596. );
  597. private static $has_one = array(
  598. 'Page' => 'VersionedOwnershipTest_Subclass'
  599. );
  600. private static $owned_by = array(
  601. 'Page'
  602. );
  603. }
  604. /**
  605. * @mixin Versioned
  606. */
  607. class VersionedOwnershipTest_Attachment extends DataObject implements TestOnly {
  608. private static $extensions = array(
  609. 'SilverStripe\\ORM\\Versioning\\Versioned',
  610. );
  611. private static $db = array(
  612. 'Title' => 'Varchar(255)',
  613. );
  614. private static $belongs_many_many = array(
  615. 'AttachedTo' => 'VersionedOwnershipTest_Related.Attachments'
  616. );
  617. private static $owned_by = array(
  618. 'AttachedTo'
  619. );
  620. }
  621. /**
  622. * Page which owns a lits of banners
  623. *
  624. * @mixin Versioned
  625. */
  626. class VersionedOwnershipTest_Page extends DataObject implements TestOnly {
  627. private static $extensions = array(
  628. 'SilverStripe\\ORM\\Versioning\\Versioned',
  629. );
  630. private static $db = array(
  631. 'Title' => 'Varchar(255)',
  632. );
  633. private static $many_many = array(
  634. 'Banners' => 'VersionedOwnershipTest_Banner',
  635. );
  636. private static $owns = array(
  637. 'Banners',
  638. 'Custom'
  639. );
  640. /**
  641. * All custom objects with the same number. E.g. 'Page 1' owns 'Custom 1'
  642. *
  643. * @return DataList
  644. */
  645. public function Custom() {
  646. $title = str_replace('Page', 'Custom', $this->Title);
  647. return VersionedOwnershipTest_CustomRelation::get()
  648. ->filter('Title', $title);
  649. }
  650. }
  651. /**
  652. * Banner which doesn't declare its belongs_many_many, but owns an Image
  653. *
  654. * @mixin Versioned
  655. */
  656. class VersionedOwnershipTest_Banner extends DataObject implements TestOnly {
  657. private static $extensions = array(
  658. 'SilverStripe\\ORM\\Versioning\\Versioned',
  659. );
  660. private static $db = array(
  661. 'Title' => 'Varchar(255)',
  662. );
  663. private static $has_one = array(
  664. 'Image' => 'VersionedOwnershipTest_Image',
  665. );
  666. private static $owns = array(
  667. 'Image',
  668. );
  669. }
  670. /**
  671. * Object which is owned via a custom PHP method rather than DB relation
  672. *
  673. * @mixin Versioned
  674. */
  675. class VersionedOwnershipTest_CustomRelation extends DataObject implements TestOnly {
  676. private static $extensions = array(
  677. 'SilverStripe\\ORM\\Versioning\\Versioned',
  678. );
  679. private static $db = array(
  680. 'Title' => 'Varchar(255)',
  681. );
  682. private static $owned_by = array(
  683. 'Pages'
  684. );
  685. /**
  686. * All pages with the same number. E.g. 'Page 1' owns 'Custom 1'
  687. *
  688. * @return DataList
  689. */
  690. public function Pages() {
  691. $title = str_replace('Custom', 'Page', $this->Title);
  692. return VersionedOwnershipTest_Page::get()->filter('Title', $title);
  693. }
  694. }
  695. /**
  696. * Simple versioned dataobject
  697. *
  698. * @mixin Versioned
  699. */
  700. class VersionedOwnershipTest_Image extends DataObject implements TestOnly {
  701. private static $extensions = array(
  702. 'SilverStripe\\ORM\\Versioning\\Versioned',
  703. );
  704. private static $db = array(
  705. 'Title' => 'Varchar(255)',
  706. );
  707. }