From 37e128d3c1402cb75519eb3ba68ed2f50ee9cf49 Mon Sep 17 00:00:00 2001 From: Andreas Lutro Date: Tue, 15 Jul 2014 08:38:12 +0200 Subject: [PATCH] Fix form model binding Form model binding now works properly with a mix of nested arrays, objects and Eloquent collections --- src/Illuminate/Html/FormBuilder.php | 35 +++++++++++++++++++++++------ tests/Html/FormBuilderTest.php | 31 +++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/src/Illuminate/Html/FormBuilder.php b/src/Illuminate/Html/FormBuilder.php index 6e22577894e3..6f186b4a8b64 100755 --- a/src/Illuminate/Html/FormBuilder.php +++ b/src/Illuminate/Html/FormBuilder.php @@ -3,6 +3,7 @@ use Illuminate\Routing\UrlGenerator; use Illuminate\Session\Store as Session; use Illuminate\Support\Traits\MacroableTrait; +use Illuminate\Database\Eloquent\Collection as EloquentCollection; class FormBuilder { @@ -897,18 +898,38 @@ public function getValueAttribute($name, $value = null) * Get the model value that should be assigned to the field. * * @param string $name - * @return string + * @return string|null */ protected function getModelValueAttribute($name) { - if (is_object($this->model)) - { - return object_get($this->model, $this->transformKey($name)); - } - elseif (is_array($this->model)) + $segments = explode('.', $this->transformKey($name)); + $data = $this->model; + + foreach ($segments as $key) { - return array_get($this->model, $this->transformKey($name)); + if (is_array($data)) + { + $data = array_key_exists($key, $data) ? $data[$key] : null; + } + elseif ($data instanceof EloquentCollection) + { + $data = $data->find($key); + } + elseif ($data instanceof \ArrayAccess) + { + $data = $data->offsetExists($key) ? $data->offsetGet($key) : null; + } + elseif (is_object($data)) + { + $data = isset($data->$key) ? $data->$key : null; + } + else + { + return null; + } } + + return $data; } /** diff --git a/tests/Html/FormBuilderTest.php b/tests/Html/FormBuilderTest.php index 601768038a70..8e00490f7e94 100755 --- a/tests/Html/FormBuilderTest.php +++ b/tests/Html/FormBuilderTest.php @@ -403,6 +403,31 @@ public function testImageInput() $this->assertEquals('', $image); } + + public function testNestedObjectsAndArrays() + { + $obj = new \StdClass; + $obj->stuff = new \Illuminate\Support\Collection([5 => ['bar' => 'baz']]); + $model = ['foo' => $obj]; + $this->formBuilder->setModel($model); + $input = $this->formBuilder->text('foo[stuff][5][bar]'); + $this->assertContains('value="baz"', $input); + } + + + public function testEloquentRelationshipValues() + { + $model = new \StdClass; + $related = [new FormBuilderModelStub(['id' => 1, 'name' => 'foo']), new FormBuilderModelStub(['id' => 2, 'name' => 'bar'])]; + $model->related = new \Illuminate\Database\Eloquent\Collection($related); + $this->formBuilder->setModel($model); + $this->assertNotContains('value=', $this->formBuilder->text('related[0][name]')); + $this->assertContains('value="foo"', $this->formBuilder->text('related[1][name]')); + $this->assertContains('value="bar"', $this->formBuilder->text('related[2][name]')); + $this->assertNotContains('value=', $this->formBuilder->text('related[3][name]')); + } + + protected function setModel(array $data, $object = true) { if ($object) $data = new FormBuilderModelStub($data); @@ -436,4 +461,10 @@ public function __isset($key) { return isset($this->data[$key]); } + + + public function getKey() + { + return isset($this->data['id']) ? $this->data['id'] : null; + } }