From 22efd3848e20b60cdc4173225ee84b2d86ab0be2 Mon Sep 17 00:00:00 2001 From: Stig Lindqvist Date: Wed, 19 Dec 2012 16:40:13 +1300 Subject: [PATCH] BUG Calling DataObject::relField() on a object with an empty relation list This causes a 'Fatal error: Call to a member function hasMethod() on a non-object'. This can happen when displaying a field in a gridfield on a belongs_to relationship. --- model/DataObject.php | 30 ++++++++++++++++++------------ tests/model/DataObjectTest.php | 3 +++ 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/model/DataObject.php b/model/DataObject.php index 27ae22fe0..ad4324e63 100644 --- a/model/DataObject.php +++ b/model/DataObject.php @@ -2619,27 +2619,33 @@ class DataObject extends ViewableData implements DataObjectInterface, i18nEntity * The path to the related field is specified with dot separated syntax (eg: Parent.Child.Child.FieldName) * * @param $fieldPath string - * @return string + * @return string | null - will return null on a missing value */ public function relField($fieldName) { $component = $this; + // We're dealing with relations here so we traverse the dot syntax if(strpos($fieldName, '.') !== false) { - $parts = explode('.', $fieldName); - $fieldName = array_pop($parts); - - // Traverse dot syntax - foreach($parts as $relation) { - if($component instanceof SS_List) { - if(method_exists($component,$relation)) $component = $component->$relation(); - else $component = $component->relation($relation); - } else { + $relations = explode('.', $fieldName); + $fieldName = array_pop($relations); + foreach($relations as $relation) { + // Bail if any of the below sets a $component to a null object + if($component instanceof SS_List && !method_exists($component, $relation)) { + $component = $component->relation($relation); + // Just call the method and hope for the best + } else { $component = $component->$relation(); } } } - - if ($component->hasMethod($fieldName)) return $component->$fieldName(); + + // Bail if the component is null + if(!$component) { + return null; + } + if($component->hasMethod($fieldName)) { + return $component->$fieldName(); + } return $component->$fieldName; } diff --git a/tests/model/DataObjectTest.php b/tests/model/DataObjectTest.php index 6942dda02..ca4bb9a97 100644 --- a/tests/model/DataObjectTest.php +++ b/tests/model/DataObjectTest.php @@ -1091,6 +1091,9 @@ class DataObjectTest extends SapphireTest { $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')); + + $newPlayer = new DataObjectTest_Player(); + $this->assertNull($newPlayer->relField('Teams.First.Title')); } public function testRelObject() {