2008-01-09 04:39:05 +01:00
< ? php
/**
2008-06-15 15:33:53 +02:00
* @ package sapphire
* @ subpackage tests
2008-01-09 04:39:05 +01:00
*/
class DataObjectTest extends SapphireTest {
2009-06-04 23:00:41 +02:00
2008-01-09 04:39:05 +01:00
static $fixture_file = 'sapphire/tests/DataObjectTest.yml' ;
2009-03-04 04:44:11 +01:00
2008-01-09 04:39:05 +01:00
/**
* Test deletion of DataObjects
* - Deleting using delete () on the DataObject
* - Deleting using DataObject :: delete_by_id ()
*/
function testDelete () {
// Test deleting using delete() on the DataObject
// Get the first page
2009-07-08 02:06:16 +02:00
$page = $this -> objFromFixture ( 'Page' , 'page1' );
2009-07-08 04:54:01 +02:00
$pageID = $page -> ID ;
2008-01-09 04:39:05 +01:00
// Check the page exists before deleting
$this -> assertTrue ( is_object ( $page ) && $page -> exists ());
// Delete the page
$page -> delete ();
// Check that page does not exist after deleting
2009-07-08 04:54:01 +02:00
$page = DataObject :: get_by_id ( 'Page' , $pageID );
2008-01-09 04:39:05 +01:00
$this -> assertTrue ( ! $page || ! $page -> exists ());
// Test deleting using DataObject::delete_by_id()
// Get the second page
2009-07-08 02:06:16 +02:00
$page2 = $this -> objFromFixture ( 'Page' , 'page2' );
2009-07-08 04:54:01 +02:00
$page2ID = $page2 -> ID ;
2008-01-09 04:39:05 +01:00
// Check the page exists before deleting
$this -> assertTrue ( is_object ( $page2 ) && $page2 -> exists ());
// Delete the page
DataObject :: delete_by_id ( 'Page' , $page2 -> ID );
// Check that page does not exist after deleting
2009-07-08 04:54:01 +02:00
$page2 = DataObject :: get_by_id ( 'Page' , $page2ID );
2008-01-09 04:39:05 +01:00
$this -> assertTrue ( ! $page2 || ! $page2 -> exists ());
}
/**
* Test methods that get DataObjects
* - DataObject :: get ()
* - All records of a DataObject
* - Filtering
* - Sorting
* - Joins
* - Limit
* - Container class
* - DataObject :: get_by_id ()
* - DataObject :: get_by_url ()
* - DataObject :: get_one ()
* - With and without caching
* - With and without ordering
*/
function testGet () {
// Test getting all records of a DataObject
$comments = DataObject :: get ( 'PageComment' );
2008-08-13 02:44:52 +02:00
$this -> assertEquals ( 8 , $comments -> Count ());
2008-01-09 04:39:05 +01:00
// Test WHERE clause
2008-11-24 10:31:14 +01:00
$comments = DataObject :: get ( 'PageComment' , " \" Name \" ='Bob' " );
2008-08-13 02:44:52 +02:00
$this -> assertEquals ( 2 , $comments -> Count ());
2008-01-09 04:39:05 +01:00
foreach ( $comments as $comment ) {
2008-08-13 02:44:52 +02:00
$this -> assertEquals ( 'Bob' , $comment -> Name );
2008-01-09 04:39:05 +01:00
}
// Test sorting
2008-11-24 10:31:14 +01:00
$comments = DataObject :: get ( 'PageComment' , '' , '"Name" ASC' );
2008-08-13 02:44:52 +02:00
$this -> assertEquals ( 8 , $comments -> Count ());
$this -> assertEquals ( 'Bob' , $comments -> First () -> Name );
2008-11-24 10:31:14 +01:00
$comments = DataObject :: get ( 'PageComment' , '' , '"Name" DESC' );
2008-08-13 02:44:52 +02:00
$this -> assertEquals ( 8 , $comments -> Count ());
$this -> assertEquals ( 'Joe' , $comments -> First () -> Name );
2008-01-09 04:39:05 +01:00
// Test join
2008-11-24 10:31:14 +01:00
$comments = DataObject :: get ( 'PageComment' , " \" SiteTree \" . \" Title \" ='First Page' " , '' , 'INNER JOIN "SiteTree" ON "PageComment"."ParentID" = "SiteTree"."ID"' );
2008-08-13 02:44:52 +02:00
$this -> assertEquals ( 2 , $comments -> Count ());
$this -> assertEquals ( 'Bob' , $comments -> First () -> Name );
$this -> assertEquals ( 'Bob' , $comments -> Last () -> Name );
2008-01-09 04:39:05 +01:00
// Test limit
2008-11-24 10:31:14 +01:00
$comments = DataObject :: get ( 'PageComment' , '' , '"Name" ASC' , '' , '1,2' );
2008-08-13 02:44:52 +02:00
$this -> assertEquals ( 2 , $comments -> Count ());
$this -> assertEquals ( 'Bob' , $comments -> First () -> Name );
$this -> assertEquals ( 'Dean' , $comments -> Last () -> Name );
2008-01-09 04:39:05 +01:00
// Test container class
$comments = DataObject :: get ( 'PageComment' , '' , '' , '' , '' , 'DataObjectSet' );
2008-08-13 02:44:52 +02:00
$this -> assertEquals ( 'DataObjectSet' , get_class ( $comments ));
2008-01-09 04:39:05 +01:00
$comments = DataObject :: get ( 'PageComment' , '' , '' , '' , '' , 'ComponentSet' );
2008-08-13 02:44:52 +02:00
$this -> assertEquals ( 'ComponentSet' , get_class ( $comments ));
2008-01-09 04:39:05 +01:00
// Test get_by_id()
2008-08-13 02:44:52 +02:00
$homepageID = $this -> idFromFixture ( 'Page' , 'home' );
$page = DataObject :: get_by_id ( 'Page' , $homepageID );
$this -> assertEquals ( 'Home' , $page -> Title );
2008-01-09 04:39:05 +01:00
// Test get_by_url()
2008-11-02 01:24:23 +01:00
$page = SiteTree :: get_by_url ( 'home' );
2008-08-13 02:44:52 +02:00
$this -> assertEquals ( $homepageID , $page -> ID );
2008-01-09 04:39:05 +01:00
// Test get_one() without caching
2008-11-24 10:31:14 +01:00
$comment1 = DataObject :: get_one ( 'PageComment' , " \" Name \" ='Joe' " , false );
2008-01-09 04:39:05 +01:00
$comment1 -> Comment = " Something Else " ;
2008-11-24 10:31:14 +01:00
$comment2 = DataObject :: get_one ( 'PageComment' , " \" Name \" ='Joe' " , false );
2008-08-13 02:44:52 +02:00
$this -> assertNotEquals ( $comment1 -> Comment , $comment2 -> Comment );
2008-01-09 04:39:05 +01:00
// Test get_one() with caching
2008-11-24 10:31:14 +01:00
$comment1 = DataObject :: get_one ( 'PageComment' , " \" Name \" ='Jane' " , true );
2008-01-09 04:39:05 +01:00
$comment1 -> Comment = " Something Else " ;
2008-11-24 10:31:14 +01:00
$comment2 = DataObject :: get_one ( 'PageComment' , " \" Name \" ='Jane' " , true );
2008-08-13 02:44:52 +02:00
$this -> assertEquals (( string ) $comment1 -> Comment , ( string ) $comment2 -> Comment );
2008-01-09 04:39:05 +01:00
// Test get_one() with order by without caching
2008-11-24 10:31:14 +01:00
$comment = DataObject :: get_one ( 'PageComment' , '' , false , '"Name" ASC' );
2008-08-13 02:44:52 +02:00
$this -> assertEquals ( 'Bob' , $comment -> Name );
2008-11-24 10:31:14 +01:00
$comment = DataObject :: get_one ( 'PageComment' , '' , false , '"Name" DESC' );
2008-08-13 02:44:52 +02:00
$this -> assertEquals ( 'Joe' , $comment -> Name );
2008-01-09 04:39:05 +01:00
// Test get_one() with order by with caching
2008-11-24 10:31:14 +01:00
$comment = DataObject :: get_one ( 'PageComment' , '' , true , '"Name" ASC' );
2008-08-13 02:44:52 +02:00
$this -> assertEquals ( 'Bob' , $comment -> Name );
2008-11-24 10:31:14 +01:00
$comment = DataObject :: get_one ( 'PageComment' , '' , true , '"Name" DESC' );
2008-08-13 02:44:52 +02:00
$this -> assertEquals ( 'Joe' , $comment -> Name );
2008-01-09 04:39:05 +01:00
}
2008-08-09 05:54:55 +02:00
/**
* Test writing of database columns which don ' t correlate to a DBField ,
* e . g . all relation fields on has_one / has_many like " ParentID " .
*
*/
function testWritePropertyWithoutDBField () {
2009-07-08 02:06:16 +02:00
$page = $this -> objFromFixture ( 'Page' , 'page1' );
2008-08-09 05:54:55 +02:00
$page -> ParentID = 99 ;
$page -> write ();
// reload the page from the database
$savedPage = DataObject :: get_by_id ( 'Page' , $page -> ID );
$this -> assertTrue ( $savedPage -> ParentID == 99 );
}
2008-01-09 04:39:05 +01:00
/**
* Test has many relationships
* - Test getComponents () gets the ComponentSet of the other side of the relation
* - Test the IDs on the DataObjects are set correctly
*/
function testHasManyRelationships () {
2009-07-08 02:06:16 +02:00
$page = $this -> objFromFixture ( 'Page' , 'home' );
2008-01-09 04:39:05 +01:00
// Test getComponents() gets the ComponentSet of the other side of the relation
$this -> assertTrue ( $page -> getComponents ( 'Comments' ) -> Count () == 2 );
// Test the IDs on the DataObjects are set correctly
foreach ( $page -> getComponents ( 'Comments' ) as $comment ) {
$this -> assertTrue ( $comment -> ParentID == $page -> ID );
}
}
2009-05-21 02:14:47 +02:00
function testHasOneRelationship () {
2009-07-08 02:06:16 +02:00
$team1 = $this -> objFromFixture ( 'DataObjectTest_Team' , 'team1' );
$player1 = $this -> objFromFixture ( 'DataObjectTest_Player' , 'player1' );
2009-05-21 02:14:47 +02:00
// Add a captain to team 1
$team1 -> setField ( 'CaptainID' , $player1 -> ID );
$team1 -> write ();
$this -> assertEquals ( $player1 -> ID , $team1 -> Captain () -> ID , 'The captain exists for team 1' );
$this -> assertEquals ( $player1 -> ID , $team1 -> getComponent ( 'Captain' ) -> ID , 'The captain exists through the component getter' );
$this -> assertEquals ( $team1 -> Captain () -> FirstName , 'Player 1' , 'Player 1 is the captain' );
$this -> assertEquals ( $team1 -> getComponent ( 'Captain' ) -> FirstName , 'Player 1' , 'Player 1 is the captain' );
}
2008-08-11 05:03:52 +02:00
/**
* @ todo Test removeMany () and addMany () on $many_many relationships
*/
function testManyManyRelationships () {
2009-07-08 02:06:16 +02:00
$player1 = $this -> objFromFixture ( 'DataObjectTest_Player' , 'player1' );
$player2 = $this -> objFromFixture ( 'DataObjectTest_Player' , 'player2' );
$team1 = $this -> objFromFixture ( 'DataObjectTest_Team' , 'team1' );
$team2 = $this -> objFromFixture ( 'DataObjectTest_Team' , 'team2' );
2008-08-11 05:03:52 +02:00
// Test adding single DataObject by reference
$player1 -> Teams () -> add ( $team1 );
$player1 -> flushCache ();
$compareTeams = new ComponentSet ( $team1 );
$this -> assertEquals (
$player1 -> Teams () -> column ( 'ID' ),
$compareTeams -> column ( 'ID' ),
" Adding single record as DataObject to many_many "
);
// test removing single DataObject by reference
$player1 -> Teams () -> remove ( $team1 );
$player1 -> flushCache ();
$compareTeams = new ComponentSet ();
$this -> assertEquals (
$player1 -> Teams () -> column ( 'ID' ),
$compareTeams -> column ( 'ID' ),
" Removing single record as DataObject from many_many "
);
// test adding single DataObject by ID
$player1 -> Teams () -> add ( $team1 -> ID );
$player1 -> flushCache ();
$compareTeams = new ComponentSet ( $team1 );
$this -> assertEquals (
$player1 -> Teams () -> column ( 'ID' ),
$compareTeams -> column ( 'ID' ),
" Adding single record as ID to many_many "
);
// test removing single DataObject by ID
$player1 -> Teams () -> remove ( $team1 -> ID );
$player1 -> flushCache ();
$compareTeams = new ComponentSet ();
$this -> assertEquals (
$player1 -> Teams () -> column ( 'ID' ),
$compareTeams -> column ( 'ID' ),
" Removing single record as ID from many_many "
);
}
/**
* @ todo Extend type change tests ( e . g . '0' == NULL )
*/
function testChangedFields () {
2009-07-08 02:06:16 +02:00
$page = $this -> objFromFixture ( 'Page' , 'home' );
2008-08-11 05:03:52 +02:00
$page -> Title = 'Home-Changed' ;
$page -> ShowInMenus = true ;
$this -> assertEquals (
$page -> getChangedFields ( false , 1 ),
array (
'Title' => array (
'before' => 'Home' ,
'after' => 'Home-Changed' ,
'level' => 2
),
'ShowInMenus' => array (
'before' => 1 ,
'after' => true ,
'level' => 1
)
),
'Changed fields are correctly detected with strict type changes (level=1)'
);
$this -> assertEquals (
$page -> getChangedFields ( false , 2 ),
array (
'Title' => array (
'before' => 'Home' ,
'after' => 'Home-Changed' ,
'level' => 2
)
),
'Changed fields are correctly detected while ignoring type changes (level=2)'
);
2008-10-08 04:00:12 +02:00
$newPage = new Page ();
$newPage -> Title = " New Page Title " ;
$this -> assertEquals (
$newPage -> getChangedFields ( false , 2 ),
array (
'Title' => array (
'before' => null ,
'after' => 'New Page Title' ,
'level' => 2
)
),
'Initialised fields are correctly detected as full changes'
);
2008-08-11 05:03:52 +02:00
}
2008-08-13 02:44:52 +02:00
2009-05-27 02:09:23 +02:00
function testIsChanged () {
2009-07-08 02:06:16 +02:00
$page = $this -> objFromFixture ( 'Page' , 'home' );
2009-05-27 02:09:23 +02:00
$page -> Title = 'Home-Changed' ;
$page -> ShowInMenus = true ; // type change only, database stores "1"
$this -> assertTrue ( $page -> isChanged ( 'Title' , 1 ));
$this -> assertTrue ( $page -> isChanged ( 'Title' , 2 ));
$this -> assertTrue ( $page -> isChanged ( 'ShowInMenus' , 1 ));
$this -> assertFalse ( $page -> isChanged ( 'ShowInMenus' , 2 ));
$this -> assertFalse ( $page -> isChanged ( 'Content' , 1 ));
$this -> assertFalse ( $page -> isChanged ( 'Content' , 2 ));
$newPage = new Page ();
$newPage -> Title = " New Page Title " ;
$this -> assertTrue ( $newPage -> isChanged ( 'Title' , 1 ));
$this -> assertTrue ( $newPage -> isChanged ( 'Title' , 2 ));
$this -> assertFalse ( $newPage -> isChanged ( 'Content' , 1 ));
$this -> assertFalse ( $newPage -> isChanged ( 'Content' , 2 ));
$newPage -> write ();
$this -> assertFalse ( $newPage -> isChanged ( 'Title' , 1 ));
$this -> assertFalse ( $newPage -> isChanged ( 'Title' , 2 ));
$this -> assertFalse ( $newPage -> isChanged ( 'Content' , 1 ));
$this -> assertFalse ( $newPage -> isChanged ( 'Content' , 2 ));
2009-07-08 02:06:16 +02:00
$page = $this -> objFromFixture ( 'Page' , 'home' );
2009-05-27 02:09:23 +02:00
$page -> Title = null ;
$this -> assertTrue ( $page -> isChanged ( 'Title' , 1 ));
$this -> assertTrue ( $page -> isChanged ( 'Title' , 2 ));
}
2008-08-13 02:44:52 +02:00
function testRandomSort () {
/* If we perforn the same regularly sorted query twice, it should return the same results */
$itemsA = DataObject :: get ( " PageComment " , " " , " ID " );
foreach ( $itemsA as $item ) $keysA [] = $item -> ID ;
$itemsB = DataObject :: get ( " PageComment " , " " , " ID " );
foreach ( $itemsB as $item ) $keysB [] = $item -> ID ;
$this -> assertEquals ( $keysA , $keysB );
/* If we perform the same random query twice, it shouldn't return the same results */
2009-09-17 02:04:09 +02:00
$itemsA = DataObject :: get ( " PageComment " , " " , DB :: getConn () -> random ());
2008-08-13 02:44:52 +02:00
foreach ( $itemsA as $item ) $keysA [] = $item -> ID ;
2009-09-17 02:04:09 +02:00
$itemsB = DataObject :: get ( " PageComment " , " " , DB :: getConn () -> random ());
2008-08-13 02:44:52 +02:00
foreach ( $itemsB as $item ) $keysB [] = $item -> ID ;
$this -> assertNotEquals ( $keysA , $keysB );
}
2008-08-15 05:08:03 +02:00
function testWriteSavesToHasOneRelations () {
/* DataObject::write() should save to a has_one relationship if you set a field called (relname)ID */
$team = new DataObjectTest_Team ();
$captainID = $this -> idFromFixture ( 'DataObjectTest_Player' , 'player1' );
$team -> CaptainID = $captainID ;
$team -> write ();
2008-11-24 10:31:14 +01:00
$this -> assertEquals ( $captainID , DB :: query ( " SELECT \" CaptainID \" FROM \" DataObjectTest_Team \" WHERE \" ID \" = $team->ID " ) -> value ());
2008-08-15 05:08:03 +02:00
/* After giving it a value, you should also be able to set it back to null */
$team -> CaptainID = '' ;
$team -> write ();
2008-11-24 10:31:14 +01:00
$this -> assertEquals ( 0 , DB :: query ( " SELECT \" CaptainID \" FROM \" DataObjectTest_Team \" WHERE \" ID \" = $team->ID " ) -> value ());
2008-08-15 05:08:03 +02:00
/* You should also be able to save a blank to it when it's first created */
$team = new DataObjectTest_Team ();
$team -> CaptainID = '' ;
$team -> write ();
2008-11-24 10:31:14 +01:00
$this -> assertEquals ( 0 , DB :: query ( " SELECT \" CaptainID \" FROM \" DataObjectTest_Team \" WHERE \" ID \" = $team->ID " ) -> value ());
2008-08-15 05:08:03 +02:00
/* Ditto for existing records without a value */
$existingTeam = $this -> objFromFixture ( 'DataObjectTest_Team' , 'team1' );
$existingTeam -> CaptainID = '' ;
$existingTeam -> write ();
2008-11-24 10:31:14 +01:00
$this -> assertEquals ( 0 , DB :: query ( " SELECT \" CaptainID \" FROM \" DataObjectTest_Team \" WHERE \" ID \" = $existingTeam->ID " ) -> value ());
2008-08-15 05:08:03 +02:00
}
2008-09-30 02:20:30 +02:00
2008-10-02 02:45:13 +02:00
function testCanAccessHasOneObjectsAsMethods () {
/* If you have a has_one relation 'Captain' on $obj , and you set the $obj -> CaptainID = ( ID ), then the object itself should
* be accessible as $obj -> Captain () */
$team = $this -> objFromFixture ( 'DataObjectTest_Team' , 'team1' );
$captainID = $this -> idFromFixture ( 'DataObjectTest_Player' , 'captain1' );
$team -> CaptainID = $captainID ;
$this -> assertNotNull ( $team -> Captain ());
$this -> assertEquals ( $captainID , $team -> Captain () -> ID );
}
2008-10-01 02:55:25 +02:00
function testFieldNamesThatMatchMethodNamesWork () {
/* Check that a field name that corresponds to a method on DataObject will still work */
2009-06-16 04:56:59 +02:00
$obj = new DataObjectTest_Fixture ();
2008-10-01 02:55:25 +02:00
$obj -> Data = " value1 " ;
$obj -> DbObject = " value2 " ;
$obj -> Duplicate = " value3 " ;
$obj -> write ();
$this -> assertNotNull ( $obj -> ID );
2009-06-16 04:56:59 +02:00
$this -> assertEquals ( 'value1' , DB :: query ( " SELECT \" Data \" FROM \" DataObjectTest_Fixture \" WHERE \" ID \" = $obj->ID " ) -> value ());
$this -> assertEquals ( 'value2' , DB :: query ( " SELECT \" DbObject \" FROM \" DataObjectTest_Fixture \" WHERE \" ID \" = $obj->ID " ) -> value ());
$this -> assertEquals ( 'value3' , DB :: query ( " SELECT \" Duplicate \" FROM \" DataObjectTest_Fixture \" WHERE \" ID \" = $obj->ID " ) -> value ());
2008-10-01 02:55:25 +02:00
}
2008-09-30 02:27:22 +02:00
/**
* @ todo Re - enable all test cases for field existence after behaviour has been fixed
*/
2008-09-30 02:20:30 +02:00
function testFieldExistence () {
$teamInstance = $this -> objFromFixture ( 'DataObjectTest_Team' , 'team1' );
$teamSingleton = singleton ( 'DataObjectTest_Team' );
$subteamInstance = $this -> objFromFixture ( 'DataObjectTest_SubTeam' , 'subteam1' );
$subteamSingleton = singleton ( 'DataObjectTest_SubTeam' );
/* hasField() singleton checks */
$this -> assertTrue ( $teamSingleton -> hasField ( 'ID' ), 'hasField() finds built-in fields in singletons' );
$this -> assertTrue ( $teamSingleton -> hasField ( 'Title' ), 'hasField() finds custom fields in singletons' );
/* hasField() instance checks */
$this -> assertFalse ( $teamInstance -> hasField ( 'NonExistingField' ), 'hasField() doesnt find non-existing fields in instances' );
$this -> assertTrue ( $teamInstance -> hasField ( 'ID' ), 'hasField() finds built-in fields in instances' );
$this -> assertTrue ( $teamInstance -> hasField ( 'Created' ), 'hasField() finds built-in fields in instances' );
$this -> assertTrue ( $teamInstance -> hasField ( 'DatabaseField' ), 'hasField() finds custom fields in instances' );
//$this->assertFalse($teamInstance->hasField('SubclassDatabaseField'), 'hasField() doesnt find subclass fields in parentclass instances');
2008-10-09 16:38:46 +02:00
$this -> assertTrue ( $teamInstance -> hasField ( 'DynamicField' ), 'hasField() finds dynamic getters in instances' );
2008-09-30 02:20:30 +02:00
$this -> assertTrue ( $teamInstance -> hasField ( 'HasOneRelationshipID' ), 'hasField() finds foreign keys in instances' );
$this -> assertTrue ( $teamInstance -> hasField ( 'DecoratedDatabaseField' ), 'hasField() finds decorated fields in instances' );
$this -> assertTrue ( $teamInstance -> hasField ( 'DecoratedHasOneRelationshipID' ), 'hasField() finds decorated foreign keys in instances' );
//$this->assertTrue($teamInstance->hasField('DecoratedDynamicField'), 'hasField() includes decorated dynamic getters in instances');
/* hasField() subclass checks */
$this -> assertTrue ( $subteamInstance -> hasField ( 'ID' ), 'hasField() finds built-in fields in subclass instances' );
$this -> assertTrue ( $subteamInstance -> hasField ( 'Created' ), 'hasField() finds built-in fields in subclass instances' );
$this -> assertTrue ( $subteamInstance -> hasField ( 'DatabaseField' ), 'hasField() finds custom fields in subclass instances' );
$this -> assertTrue ( $subteamInstance -> hasField ( 'SubclassDatabaseField' ), 'hasField() finds custom fields in subclass instances' );
2008-10-09 16:38:46 +02:00
$this -> assertTrue ( $subteamInstance -> hasField ( 'DynamicField' ), 'hasField() finds dynamic getters in subclass instances' );
2008-09-30 02:20:30 +02:00
$this -> assertTrue ( $subteamInstance -> hasField ( 'HasOneRelationshipID' ), 'hasField() finds foreign keys in subclass instances' );
$this -> assertTrue ( $subteamInstance -> hasField ( 'DecoratedDatabaseField' ), 'hasField() finds decorated fields in subclass instances' );
$this -> assertTrue ( $subteamInstance -> hasField ( 'DecoratedHasOneRelationshipID' ), 'hasField() finds decorated foreign keys in subclass instances' );
/* hasDatabaseField() singleton checks */
//$this->assertTrue($teamSingleton->hasDatabaseField('ID'), 'hasDatabaseField() finds built-in fields in singletons');
$this -> assertTrue ( $teamSingleton -> hasDatabaseField ( 'Title' ), 'hasDatabaseField() finds custom fields in singletons' );
/* hasDatabaseField() instance checks */
$this -> assertFalse ( $teamInstance -> hasDatabaseField ( 'NonExistingField' ), 'hasDatabaseField() doesnt find non-existing fields in instances' );
//$this->assertTrue($teamInstance->hasDatabaseField('ID'), 'hasDatabaseField() finds built-in fields in instances');
$this -> assertTrue ( $teamInstance -> hasDatabaseField ( 'Created' ), 'hasDatabaseField() finds built-in fields in instances' );
$this -> assertTrue ( $teamInstance -> hasDatabaseField ( 'DatabaseField' ), 'hasDatabaseField() finds custom fields in instances' );
$this -> assertFalse ( $teamInstance -> hasDatabaseField ( 'SubclassDatabaseField' ), 'hasDatabaseField() doesnt find subclass fields in parentclass instances' );
//$this->assertFalse($teamInstance->hasDatabaseField('DynamicField'), 'hasDatabaseField() doesnt dynamic getters in instances');
$this -> assertTrue ( $teamInstance -> hasDatabaseField ( 'HasOneRelationshipID' ), 'hasDatabaseField() finds foreign keys in instances' );
$this -> assertTrue ( $teamInstance -> hasDatabaseField ( 'DecoratedDatabaseField' ), 'hasDatabaseField() finds decorated fields in instances' );
$this -> assertTrue ( $teamInstance -> hasDatabaseField ( 'DecoratedHasOneRelationshipID' ), 'hasDatabaseField() finds decorated foreign keys in instances' );
$this -> assertFalse ( $teamInstance -> hasDatabaseField ( 'DecoratedDynamicField' ), 'hasDatabaseField() doesnt include decorated dynamic getters in instances' );
/* hasDatabaseField() subclass checks */
$this -> assertTrue ( $subteamInstance -> hasField ( 'DatabaseField' ), 'hasField() finds custom fields in subclass instances' );
$this -> assertTrue ( $subteamInstance -> hasField ( 'SubclassDatabaseField' ), 'hasField() finds custom fields in subclass instances' );
}
2008-09-30 02:27:22 +02:00
/**
* @ todo Re - enable all test cases for field inheritance aggregation after behaviour has been fixed
*/
2008-09-30 02:20:30 +02:00
function testFieldInheritance () {
$teamInstance = $this -> objFromFixture ( 'DataObjectTest_Team' , 'team1' );
$subteamInstance = $this -> objFromFixture ( 'DataObjectTest_SubTeam' , 'subteam1' );
$this -> assertEquals (
array_keys ( $teamInstance -> inheritedDatabaseFields ()),
array (
//'ID',
//'ClassName',
//'Created',
//'LastEdited',
'Title' ,
'DatabaseField' ,
'DecoratedDatabaseField' ,
'CaptainID' ,
'HasOneRelationshipID' ,
'DecoratedHasOneRelationshipID'
),
'inheritedDatabaseFields() contains all fields defined on instance, including base fields, decorated fields and foreign keys'
);
$this -> assertEquals (
2009-08-11 10:49:52 +02:00
array_keys ( DataObject :: database_fields ( 'DataObjectTest_Team' )),
2008-09-30 02:20:30 +02:00
array (
//'ID',
'ClassName' ,
'Created' ,
'LastEdited' ,
'Title' ,
'DatabaseField' ,
'DecoratedDatabaseField' ,
'CaptainID' ,
'HasOneRelationshipID' ,
'DecoratedHasOneRelationshipID'
),
'databaseFields() contains only fields defined on instance, including base fields, decorated fields and foreign keys'
);
$this -> assertEquals (
array_keys ( $subteamInstance -> inheritedDatabaseFields ()),
array (
//'ID',
//'ClassName',
//'Created',
//'LastEdited',
'SubclassDatabaseField' ,
'Title' ,
'DatabaseField' ,
'DecoratedDatabaseField' ,
'CaptainID' ,
'HasOneRelationshipID' ,
'DecoratedHasOneRelationshipID' ,
),
'inheritedDatabaseFields() on subclass contains all fields defined on instance, including base fields, decorated fields and foreign keys'
);
$this -> assertEquals (
2009-08-11 10:49:52 +02:00
array_keys ( DataObject :: database_fields ( 'DataObjectTest_SubTeam' )),
2008-09-30 02:20:30 +02:00
array (
'SubclassDatabaseField' ,
),
'databaseFields() on subclass contains only fields defined on instance'
);
}
2008-10-02 02:45:13 +02:00
function testDataObjectUpdate () {
/* update() calls can use the dot syntax to reference has_one relations and other methods that return objects */
$team1 = $this -> objFromFixture ( 'DataObjectTest_Team' , 'team1' );
$team1 -> CaptainID = $this -> idFromFixture ( 'DataObjectTest_Player' , 'captain1' );
$team1 -> update ( array (
'DatabaseField' => 'Something' ,
'Captain.FirstName' => 'Jim' ,
'Captain.Email' => 'jim@example.com' ,
'Captain.FavouriteTeam.Title' => 'New and improved team 1' ,
));
/* Test the simple case of updating fields on the object itself */
$this -> assertEquals ( 'Something' , $team1 -> DatabaseField );
/* Setting Captain . Email and Captain . FirstName will have updated DataObjectTest_Captain . captain1 in the database . Although update ()
* doesn ' t usually write , it does write related records automatically . */
$captain1 = $this -> objFromFixture ( 'DataObjectTest_Player' , 'captain1' );
$this -> assertEquals ( 'Jim' , $captain1 -> FirstName );
$this -> assertEquals ( 'jim@example.com' , $captain1 -> Email );
/* Jim's favourite team is team 1; we need to reload the object to the the change that setting Captain.FavouriteTeam.Title made */
$reloadedTeam1 = $this -> objFromFixture ( 'DataObjectTest_Team' , 'team1' );
$this -> assertEquals ( 'New and improved team 1' , $reloadedTeam1 -> Title );
}
2009-03-04 04:44:11 +01:00
public function testWritingInvalidDataObjectThrowsException () {
$validatedObject = new DataObjectTest_ValidatedObject ();
$this -> setExpectedException ( 'ValidationException' );
$validatedObject -> write ();
}
2008-10-08 22:42:09 +02:00
2009-03-04 04:44:11 +01:00
public function testWritingValidDataObjectDoesntThrowException () {
2008-10-08 22:42:09 +02:00
$validatedObject = new DataObjectTest_ValidatedObject ();
$validatedObject -> Name = " Mr. Jones " ;
2009-03-04 04:44:11 +01:00
$validatedObject -> write ();
$this -> assertTrue ( $validatedObject -> isInDB (), " Validated object was not saved to database " );
2008-10-08 22:42:09 +02:00
}
2008-10-28 02:23:41 +01:00
public function testSubclassCreation () {
/* Creating a new object of a subclass should set the ClassName field correctly */
$obj = new DataObjectTest_SubTeam ();
$obj -> write ();
2008-11-24 10:31:14 +01:00
$this -> assertEquals ( " DataObjectTest_SubTeam " , DB :: query ( " SELECT \" ClassName \" FROM \" DataObjectTest_Team \" WHERE \" ID \" = $obj->ID " ) -> value ());
2008-10-28 02:23:41 +01:00
}
public function testForceInsert () {
/* If you set an ID on an object and pass forceInsert = true, then the object should be correctly created */
2009-05-07 08:00:50 +02:00
$conn = DB :: getConn ();
2009-08-08 06:23:05 +02:00
if ( method_exists ( $conn , 'allowPrimaryKeyEditing' )) $conn -> allowPrimaryKeyEditing ( 'DataObjectTest_Team' , true );
2008-10-28 02:23:41 +01:00
$obj = new DataObjectTest_SubTeam ();
$obj -> ID = 1001 ;
$obj -> Title = 'asdfasdf' ;
$obj -> SubclassDatabaseField = 'asdfasdf' ;
$obj -> write ( false , true );
2009-08-08 06:23:05 +02:00
if ( method_exists ( $conn , 'allowPrimaryKeyEditing' )) $conn -> allowPrimaryKeyEditing ( 'DataObjectTest_Team' , false );
2008-10-28 02:23:41 +01:00
2008-11-24 10:31:14 +01:00
$this -> assertEquals ( " DataObjectTest_SubTeam " , DB :: query ( " SELECT \" ClassName \" FROM \" DataObjectTest_Team \" WHERE \" ID \" = $obj->ID " ) -> value ());
2008-10-28 02:23:41 +01:00
/* Check that it actually saves to the database with the correct ID */
2008-11-24 10:31:14 +01:00
$this -> assertEquals ( " 1001 " , DB :: query ( " SELECT \" ID \" FROM \" DataObjectTest_SubTeam \" WHERE \" SubclassDatabaseField \" = 'asdfasdf' " ) -> value ());
$this -> assertEquals ( " 1001 " , DB :: query ( " SELECT \" ID \" FROM \" DataObjectTest_Team \" WHERE \" Title \" = 'asdfasdf' " ) -> value ());
2008-10-28 02:23:41 +01:00
}
2008-11-06 05:51:25 +01:00
public function TestHasOwnTable () {
/* Test DataObject::has_own_table() returns true if the object has $has_one or $db values */
$this -> assertTrue ( DataObject :: has_own_table ( " DataObjectTest_Player " ));
$this -> assertTrue ( DataObject :: has_own_table ( " DataObjectTest_Team " ));
2009-06-16 04:56:59 +02:00
$this -> assertTrue ( DataObject :: has_own_table ( " DataObjectTest_Fixture " ));
2008-11-06 05:51:25 +01:00
/* Root DataObject that always have a table, even if they lack both $db and $has_one */
$this -> assertTrue ( DataObject :: has_own_table ( " DataObjectTest_FieldlessTable " ));
/* Subclasses without $db or $has_one don't have a table */
$this -> assertFalse ( DataObject :: has_own_table ( " DataObjectTest_FieldlessSubTable " ));
/* Return false if you don't pass it a subclass of DataObject */
$this -> assertFalse ( DataObject :: has_own_table ( " DataObject " ));
$this -> assertFalse ( DataObject :: has_own_table ( " ViewableData " ));
$this -> assertFalse ( DataObject :: has_own_table ( " ThisIsntADataObject " ));
}
2009-01-07 02:25:43 +01:00
public function testMerge () {
// test right merge of subclasses
$left = $this -> objFromFixture ( 'DataObjectTest_SubTeam' , 'subteam1' );
$right = $this -> objFromFixture ( 'DataObjectTest_SubTeam' , 'subteam2_with_player_relation' );
$leftOrigID = $left -> ID ;
$left -> merge ( $right , 'right' , false , false );
$this -> assertEquals (
$left -> Title ,
'Subteam 2' ,
'merge() with "right" priority overwrites fields with existing values on subclasses'
);
$this -> assertEquals (
$left -> ID ,
$leftOrigID ,
'merge() with "right" priority doesnt overwrite database ID'
);
// test overwriteWithEmpty flag on existing left values
$left = $this -> objFromFixture ( 'DataObjectTest_SubTeam' , 'subteam2_with_player_relation' );
$right = $this -> objFromFixture ( 'DataObjectTest_SubTeam' , 'subteam3_with_empty_fields' );
$left -> merge ( $right , 'right' , false , true );
$this -> assertEquals (
$left -> Title ,
'Subteam 3' ,
'merge() with $overwriteWithEmpty overwrites non-empty fields on left object'
);
// test overwriteWithEmpty flag on empty left values
$left = $this -> objFromFixture ( 'DataObjectTest_SubTeam' , 'subteam1' );
$right = $this -> objFromFixture ( 'DataObjectTest_SubTeam' , 'subteam2_with_player_relation' ); // $SubclassDatabaseField is empty on here
$left -> merge ( $right , 'right' , false , true );
$this -> assertEquals (
$left -> SubclassDatabaseField ,
NULL ,
'merge() with $overwriteWithEmpty overwrites empty fields on left object'
);
// @todo test "left" priority flag
// @todo test includeRelations flag
// @todo test includeRelations in combination with overwriteWithEmpty
// @todo test has_one relations
// @todo test has_many and many_many relations
}
2009-02-10 07:04:36 +01:00
2009-03-16 14:43:03 +01:00
function testPopulateDefaults () {
2009-06-16 04:56:59 +02:00
$obj = new DataObjectTest_Fixture ();
2009-03-16 14:43:03 +01:00
$this -> assertEquals (
2009-06-16 04:56:59 +02:00
$obj -> MyFieldWithDefault ,
2009-03-16 14:43:03 +01:00
" Default Value " ,
" Defaults are populated for in-memory object from \$ defaults array "
);
}
2009-04-27 07:55:25 +02:00
function testNewClassInstance () {
2009-07-08 02:06:16 +02:00
$page = $this -> objFromFixture ( 'Page' , 'page1' );
2009-04-27 07:55:25 +02:00
$changedPage = $page -> newClassInstance ( 'RedirectorPage' );
$changedFields = $changedPage -> getChangedFields ();
// Don't write the record, it will reset changed fields
$this -> assertType ( 'RedirectorPage' , $changedPage );
$this -> assertEquals ( $changedPage -> ClassName , 'RedirectorPage' );
//$this->assertEquals($changedPage->RecordClassName, 'RedirectorPage');
$this -> assertContains ( 'ClassName' , array_keys ( $changedFields ));
$this -> assertEquals ( $changedFields [ 'ClassName' ][ 'before' ], 'Page' );
$this -> assertEquals ( $changedFields [ 'ClassName' ][ 'after' ], 'RedirectorPage' );
$changedPage -> write ();
$this -> assertType ( 'RedirectorPage' , $changedPage );
$this -> assertEquals ( $changedPage -> ClassName , 'RedirectorPage' );
}
2009-05-01 05:49:34 +02:00
function testManyManyExtraFields () {
2009-07-08 02:06:16 +02:00
$player = $this -> objFromFixture ( 'DataObjectTest_Player' , 'player1' );
$team = $this -> objFromFixture ( 'DataObjectTest_Team' , 'team1' );
2009-05-01 05:49:34 +02:00
// Extra fields are immediately available on the Team class (defined in $many_many_extraFields)
$teamExtraFields = $team -> many_many_extraFields ( 'Players' );
$this -> assertEquals ( $teamExtraFields , array (
'Position' => 'Varchar(100)'
));
// We'll have to go through the relation to get the extra fields on Player
$playerExtraFields = $player -> many_many_extraFields ( 'Teams' );
$this -> assertEquals ( $playerExtraFields , array (
'Position' => 'Varchar(100)'
));
}
2009-05-22 05:49:15 +02:00
/**
* Tests that singular_name () generates sensible defaults .
*/
public function testSingularName () {
$assertions = array (
'DataObjectTest_Player' => 'Data Object Test Player' ,
'DataObjectTest_Team' => 'Data Object Test Team' ,
2009-06-16 04:56:59 +02:00
'DataObjectTest_Fixture' => 'Data Object Test Fixture'
2009-05-22 05:49:15 +02:00
);
foreach ( $assertions as $class => $expectedSingularName ) {
$this -> assertEquals (
$expectedSingularName ,
singleton ( $class ) -> singular_name (),
" Assert that the singular_name for ' $class ' is correct. "
);
}
}
2009-06-04 23:00:41 +02:00
function testHasDatabaseField () {
2009-06-02 05:43:45 +02:00
$team = singleton ( 'DataObjectTest_Team' );
$subteam = singleton ( 'DataObjectTest_SubTeam' );
$this -> assertTrue (
$team -> hasDatabaseField ( 'Title' ),
" hasOwnDatabaseField() works with \$ db fields "
);
$this -> assertTrue (
$team -> hasDatabaseField ( 'CaptainID' ),
" hasOwnDatabaseField() works with \$ has_one fields "
);
$this -> assertFalse (
$team -> hasDatabaseField ( 'NonExistentField' ),
" hasOwnDatabaseField() doesn't detect non-existend fields "
);
$this -> assertTrue (
$team -> hasDatabaseField ( 'DecoratedDatabaseField' ),
" hasOwnDatabaseField() works with decorated fields "
);
$this -> assertFalse (
$team -> hasDatabaseField ( 'SubclassDatabaseField' ),
" hasOwnDatabaseField() doesn't pick up fields in subclasses on parent class "
);
2009-06-04 23:00:41 +02:00
$this -> assertTrue (
2009-06-02 05:43:45 +02:00
$subteam -> hasDatabaseField ( 'SubclassDatabaseField' ),
" hasOwnDatabaseField() picks up fields in subclasses "
);
}
2009-06-16 04:56:59 +02:00
function testFieldTypes () {
$obj = new DataObjectTest_Fixture ();
$obj -> DateField = '1988-01-02' ;
$obj -> DatetimeField = '1988-03-04 06:30' ;
$obj -> write ();
$obj -> flushCache ();
$obj = DataObject :: get_by_id ( 'DataObjectTest_Fixture' , $obj -> ID );
$this -> assertEquals ( '1988-01-02' , $obj -> DateField );
2009-06-16 05:21:13 +02:00
$this -> assertEquals ( '1988-03-04 06:30:00' , $obj -> DatetimeField );
2009-06-16 04:56:59 +02:00
}
2009-08-19 06:34:28 +02:00
function testTwoSubclassesWithTheSameFieldNameWork () {
// Create two objects of different subclasses, setting the values of fields that are
// defined separately in each subclass
$obj1 = new DataObjectTest_SubTeam ();
$obj1 -> SubclassDatabaseField = " obj1 " ;
$obj2 = new OtherSubclassWithSameField ();
$obj2 -> SubclassDatabaseField = " obj2 " ;
// Write them to the database
$obj1 -> write ();
$obj2 -> write ();
// Check that the values of those fields are properly read from the database
2009-09-17 02:04:09 +02:00
$values = DataObject :: get ( " DataObjectTest_Team " , " \" DataObjectTest_Team \" . \" ID \" IN
2009-08-19 06:34:28 +02:00
( $obj1 -> ID , $obj2 -> ID ) " )->column( " SubclassDatabaseField " );
$this -> assertEquals ( array ( 'obj1' , 'obj2' ), $values );
}
2009-08-21 07:02:31 +02:00
function testClassNameSetForNewObjects () {
$d = new DataObjectTest_Player ();
$this -> assertEquals ( 'DataObjectTest_Player' , $d -> ClassName );
}
2008-01-09 04:39:05 +01:00
}
2008-08-11 06:51:58 +02:00
class DataObjectTest_Player extends Member implements TestOnly {
2008-10-02 02:45:13 +02:00
static $has_one = array (
'FavouriteTeam' => 'DataObjectTest_Team' ,
);
2009-05-21 02:14:47 +02:00
2008-10-02 02:45:13 +02:00
static $belongs_many_many = array (
'Teams' => 'DataObjectTest_Team'
);
2008-08-11 06:51:58 +02:00
}
class DataObjectTest_Team extends DataObject implements TestOnly {
2008-08-15 05:08:03 +02:00
static $db = array (
2009-05-07 08:00:50 +02:00
'Title' => 'Varchar' ,
'DatabaseField' => 'Varchar'
2008-08-15 05:08:03 +02:00
);
static $has_one = array (
" Captain " => 'DataObjectTest_Player' ,
2008-09-30 02:20:30 +02:00
'HasOneRelationship' => 'DataObjectTest_Player' ,
2008-08-15 05:08:03 +02:00
);
static $many_many = array (
'Players' => 'DataObjectTest_Player'
);
2008-09-30 02:20:30 +02:00
2009-02-10 07:04:36 +01:00
static $many_many_extraFields = array (
'Players' => array (
'Position' => 'Varchar(100)'
)
);
2008-09-30 02:20:30 +02:00
function getDynamicField () {
return 'dynamicfield' ;
}
}
2009-06-16 04:56:59 +02:00
class DataObjectTest_Fixture extends DataObject implements TestOnly {
2008-10-01 02:55:25 +02:00
static $db = array (
2009-06-16 04:56:59 +02:00
// Funny field names
2009-05-07 08:00:50 +02:00
'Data' => 'Varchar' ,
'Duplicate' => 'Varchar' ,
'DbObject' => 'Varchar' ,
2009-06-16 04:56:59 +02:00
// Field with default
2009-05-07 08:00:50 +02:00
'MyField' => 'Varchar' ,
2009-06-16 04:56:59 +02:00
// Field types
" DateField " => " Date " ,
" DatetimeField " => " Datetime " ,
2009-03-16 14:43:03 +01:00
);
2009-06-16 04:56:59 +02:00
2009-03-16 14:43:03 +01:00
static $defaults = array (
2009-06-16 04:56:59 +02:00
'MyFieldWithDefault' => 'Default Value' ,
2009-03-16 14:43:03 +01:00
);
}
2008-09-30 02:20:30 +02:00
class DataObjectTest_SubTeam extends DataObjectTest_Team implements TestOnly {
static $db = array (
2009-05-07 08:00:50 +02:00
'SubclassDatabaseField' => 'Varchar'
2008-09-30 02:20:30 +02:00
);
}
2009-08-19 06:34:28 +02:00
class OtherSubclassWithSameField extends DataObjectTest_Team {
static $db = array (
'SubclassDatabaseField' => 'Varchar' ,
);
}
2008-08-15 05:08:03 +02:00
2008-11-06 05:51:25 +01:00
class DataObjectTest_FieldlessTable extends DataObject implements TestOnly {
}
class DataObjectTest_FieldlessSubTable extends DataObjectTest_Team implements TestOnly {
}
2008-09-30 02:20:30 +02:00
class DataObjectTest_Team_Decorator extends DataObjectDecorator implements TestOnly {
2008-11-02 01:36:57 +01:00
function extraStatics () {
2008-09-30 02:20:30 +02:00
return array (
'db' => array (
2009-05-07 08:00:50 +02:00
'DecoratedDatabaseField' => 'Varchar'
2008-09-30 02:20:30 +02:00
),
'has_one' => array (
'DecoratedHasOneRelationship' => 'DataObjectTest_Player'
)
);
}
function getDecoratedDynamicField () {
return " decorated dynamic field " ;
}
2008-08-11 06:51:58 +02:00
}
2008-10-08 22:42:09 +02:00
class DataObjectTest_ValidatedObject extends DataObject implements TestOnly {
static $db = array (
'Name' => 'Varchar(50)'
);
protected function validate () {
if ( ! empty ( $this -> Name )) {
return new ValidationResult ();
} else {
return new ValidationResult ( false , " This object needs a name. Otherwise it will have an identity crisis! " );
}
}
}
2008-09-30 02:20:30 +02:00
DataObject :: add_extension ( 'DataObjectTest_Team' , 'DataObjectTest_Team_Decorator' );
2008-01-09 04:39:05 +01:00
?>