Permalink
Browse files

API CHANGE: Added DataObject::relField(), which pushes the "relation …

…dot syntax" code of TableListField/GridField back to the model.

BUGFIX: Made DataObject::relObject() more flexible; allowable thanks to new ORM.
  • Loading branch information...
1 parent 1b24437 commit 2576944a45fb3804a7c952a955a6c6b3eae5927a @sminnee sminnee committed Mar 24, 2012
Showing with 64 additions and 13 deletions.
  1. +37 −13 model/DataObject.php
  2. +27 −0 tests/model/DataObjectTest.php
View
50 model/DataObject.php
@@ -2397,22 +2397,22 @@ public function dbObject($fieldName) {
* @return DBField
*/
public function relObject($fieldPath) {
- $parts = explode('.', $fieldPath);
- $fieldName = array_pop($parts);
- $component = $this;
- foreach($parts as $relation) {
- if ($rel = $component->has_one($relation)) {
- $component = singleton($rel);
- } elseif ($rel = $component->has_many($relation)) {
- $component = singleton($rel);
- } elseif ($rel = $component->many_many($relation)) {
- $component = singleton($rel[1]);
- } elseif($className = $this->castingClass($relation)) {
- $component = $className;
+ if(strpos($fieldPath, '.') !== false) {
+ $parts = explode('.', $fieldPath);
+ $fieldName = array_pop($parts);
+
+ // Traverse dot syntax
+ $component = $this;
+ foreach($parts as $relation) {
+ $component = $component->$relation();
}
+
+ $object = $component->dbObject($fieldName);
+
+ } else {
+ $object = $this->dbObject($fieldPath);
}
- $object = $component->dbObject($fieldName);
if (!($object instanceof DBField) && !($object instanceof DataList)) {
// Todo: come up with a broader range of exception objects to describe differnet kinds of errors programatically
@@ -2422,6 +2422,30 @@ public function relObject($fieldPath) {
}
/**
+ * Traverses to a field referenced by relationships between data objects, returning the value
+ * The path to the related field is specified with dot separated syntax (eg: Parent.Child.Child.FieldName)
+ *
+ * @param $fieldPath string
+ * @return string
+ */
+ public function relField($fieldPath) {
+ if(strpos($fieldPath, '.') !== false) {
+ $parts = explode('.', $fieldPath);
+ $fieldName = array_pop($parts);
+
+ // Traverse dot syntax
+ $component = $this;
+ foreach($parts as $relation) {
+ $component = $component->$relation();
+ }
+
+ return $component->$fieldName;
+ } else {
+ return $this->$fieldPath;
+ }
+ }
+
+ /**
* Temporary hack to return an association name, based on class, to get around the mangle
* of having to deal with reverse lookup of relationships to determine autogenerated foreign keys.
*
View
27 tests/model/DataObjectTest.php
@@ -1007,6 +1007,33 @@ function testIsEmpty() {
$this->assertFalse($objEmpty->isEmpty(), 'Zero value in attribute considered non-empty');
}
+ function testRelField() {
+ $captain = $this->objFromFixture('DataObjectTest_Player', 'captain1');
+ // Test traversal of a single has_one
+ $this->assertEquals("Team 1", $captain->relField('FavouriteTeam.Title'));
+ // Test direct field access
+ $this->assertEquals("Captain", $captain->relField('FirstName'));
+
+ $player = $this->objFromFixture('DataObjectTest_Player', 'player2');
+ // Test that we can traverse more than once, and that arbitrary methods are okay
+ $this->assertEquals("Team 1", $player->relField('Teams.First.Title'));
+ }
+
+ function testRelObject() {
+ $captain = $this->objFromFixture('DataObjectTest_Player', 'captain1');
+ // Test traversal of a single has_one
+ $this->assertInstanceOf("Varchar", $captain->relObject('FavouriteTeam.Title'));
+ $this->assertEquals("Team 1", $captain->relObject('FavouriteTeam.Title')->getValue());
+ // Test direct field access
+ $this->assertInstanceOf("Boolean", $captain->relObject('IsRetired'));
+ $this->assertEquals(1, $captain->relObject('IsRetired')->getValue());
+
+ $player = $this->objFromFixture('DataObjectTest_Player', 'player2');
+ // Test that we can traverse more than once, and that arbitrary methods are okay
+ $this->assertInstanceOf("Varchar", $player->relObject('Teams.First.Title'));
+ $this->assertEquals("Team 1", $player->relObject('Teams.First.Title')->getValue());
+ }
+
}

1 comment on commit 2576944

@halkyon
SilverStripe Ltd. member

@sminnee I found a SearchContext test failure from a change on line 2410 of DataObject. $component->dbObject() is being called on a HasManyList, but dbObject isn't defined.

Search Context Test::test Relationship Objects Linked In Search
Object->__call(): the method 'dbobject' does not exist on 'HasManyList'
<ul>Object->__call(dbObject,Array)
DataObject.php:2410

HasManyList->dbObject(SolutionArea)
DataObject.php:2410

DataObject->relObject(Actions.SolutionArea)
DataObject.php:1790

DataObject->scaffoldSearchFields()
DataObject.php:1736

DataObject->getDefaultSearchContext()
SearchContextTest.php:101
Please sign in to comment.