diff --git a/composer.json b/composer.json index 455add90..c43f0b86 100755 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "require-dev": { "illuminate/database": "5.7.*", "mockery/mockery": "~1.0", - "phpunit/phpunit": "~5.4" + "phpunit/phpunit": "~7.1" }, "autoload": { "psr-4": { diff --git a/phpunit.xml b/phpunit.xml index b2081a2f..87f5e0d7 100755 --- a/phpunit.xml +++ b/phpunit.xml @@ -9,8 +9,6 @@ processIsolation="false" stopOnError="false" stopOnFailure="false" - syntaxCheck="true" - strict="false" verbose="true" > diff --git a/src/FormBuilder.php b/src/FormBuilder.php index f9a5471e..f28aaba2 100644 --- a/src/FormBuilder.php +++ b/src/FormBuilder.php @@ -49,6 +49,12 @@ class FormBuilder */ protected $csrfToken; + /** + * Consider Request variables while auto fill. + * @var bool + */ + protected $considerRequest = false; + /** * The session store implementation. * @@ -108,6 +114,7 @@ class FormBuilder * @param \Illuminate\Contracts\Routing\UrlGenerator $url * @param \Illuminate\Contracts\View\Factory $view * @param string $csrfToken + * @param Request $request */ public function __construct(HtmlBuilder $html, UrlGenerator $url, Factory $view, $csrfToken, Request $request = null) { @@ -190,7 +197,7 @@ public function setModel($model) { $this->model = $model; } - + /** * Get the current model instance on the form builder. * @@ -516,7 +523,7 @@ public function week($name, $value = null, $options = []) return $this->input('week', $name, $value, $options); } - + /** * Create a file input field. * @@ -730,7 +737,7 @@ public function selectMonth($name, $selected = null, $options = [], $format = '% */ public function getSelectOption($display, $value, $selected, array $attributes = [], array $optgroupAttributes = []) { - if (is_array($display)) { + if (is_iterable($display)) { return $this->optionGroup($display, $value, $selected, $optgroupAttributes, $attributes); } @@ -755,7 +762,7 @@ protected function optionGroup($list, $label, $selected, array $attributes = [], $space = str_repeat(" ", $level); foreach ($list as $value => $display) { $optionAttributes = $optionsAttributes[$value] ?? []; - if (is_array($display)) { + if (is_iterable($display)) { $html[] = $this->optionGroup($display, $value, $selected, $attributes, $optionAttributes, $level+5); } else { $html[] = $this->option($space.$display, $value, $selected, $optionAttributes); @@ -805,7 +812,7 @@ protected function placeholderOption($display, $selected) 'value' => '', ]; - return $this->toHtmlString('html->attributes($options) . ' hidden="hidden">' . e($display, false) . ''); + return $this->toHtmlString('html->attributes($options) . '>' . e($display, false) . ''); } /** @@ -907,7 +914,7 @@ protected function getCheckedState($type, $name, $value, $checked) return $this->getRadioCheckedState($name, $value, $checked); default: - return $this->getValueAttribute($name) === $value; + return $this->compareValues($name, $value); } } @@ -960,7 +967,21 @@ protected function getRadioCheckedState($name, $value, $checked) return $checked; } - return $this->getValueAttribute($name) === $value; + return $this->compareValues($name, $value); + } + + /** + * Determine if the provide value loosely compares to the value assigned to the field. + * Use loose comparison because Laravel model casting may be in affect and therefore + * 1 == true and 0 == false. + * + * @param string $name + * @param string $value + * @return bool + */ + protected function compareValues($name, $value) + { + return $this->getValueAttribute($name) == $value; } /** @@ -1276,7 +1297,7 @@ public function getValueAttribute($name, $value = null) if ($hasNullMiddleware && is_null($old) && is_null($value) - && ! is_null($this->view->shared('errors')) + && !is_null($this->view->shared('errors')) && count($this->view->shared('errors')) > 0 ) { return null; @@ -1297,6 +1318,15 @@ public function getValueAttribute($name, $value = null) } } + /** + * Take Request in fill process + * @param bool $consider + */ + public function considerRequest($consider = true) + { + $this->considerRequest = $consider; + } + /** * Get value from current Request * @param $name @@ -1304,7 +1334,11 @@ public function getValueAttribute($name, $value = null) */ protected function request($name) { - if (! isset($this->request)) { + if (!$this->considerRequest) { + return null; + } + + if (!isset($this->request)) { return null; } @@ -1342,16 +1376,16 @@ public function old($name) $key = $this->transformKey($name); $payload = $this->session->getOldInput($key); - if (! is_array($payload)) { + if (!is_array($payload)) { return $payload; } - if (! in_array($this->type, ['select', 'checkbox'])) { - if (! isset($this->payload[$key])) { + if (!in_array($this->type, ['select', 'checkbox'])) { + if (!isset($this->payload[$key])) { $this->payload[$key] = collect($payload); } - if (! empty($this->payload[$key])) { + if (!empty($this->payload[$key])) { $value = $this->payload[$key]->shift(); return $value; } diff --git a/src/HtmlBuilder.php b/src/HtmlBuilder.php index ec953546..743b32a0 100755 --- a/src/HtmlBuilder.php +++ b/src/HtmlBuilder.php @@ -94,7 +94,7 @@ public function style($url, $attributes = [], $secure = null) { $defaults = ['media' => 'all', 'type' => 'text/css', 'rel' => 'stylesheet']; - $attributes = array_merge($attributes, $defaults); + $attributes = array_merge($defaults, $attributes); $attributes['href'] = $this->url->asset($url, $secure); @@ -455,6 +455,10 @@ protected function attributeElement($key, $value) return $value ? $key : ''; } + if (is_array($value) && $key === 'class') { + return 'class="' . implode(' ', $value) . '"'; + } + if (! is_null($value)) { return $key . '="' . e($value, false) . '"'; } diff --git a/tests/FormAccessibleTest.php b/tests/FormAccessibleTest.php index 6a737280..3471d1e8 100644 --- a/tests/FormAccessibleTest.php +++ b/tests/FormAccessibleTest.php @@ -12,7 +12,7 @@ use Illuminate\Database\Capsule\Manager as Capsule; use Mockery as m; -class FormAccessibleTest extends PHPUnit_Framework_TestCase +class FormAccessibleTest extends PHPUnit\Framework\TestCase { public function setUp() { @@ -74,12 +74,12 @@ public function testItCanGetRelatedValueForForms() $model = new ModelThatUsesForms($this->modelData); $this->assertEquals($model->getFormValue('address.street'), 'abcde st'); } - + public function testItCanUseGetAccessorValuesWhenThereAreNoFormAccessors() { $model = new ModelThatUsesForms($this->modelData); $this->formBuilder->setModel($model); - + $this->assertEquals($this->formBuilder->getValueAttribute('email'), 'mutated@tjshafer.com'); } diff --git a/tests/FormBuilderTest.php b/tests/FormBuilderTest.php index 01c0cfc5..06a8b450 100644 --- a/tests/FormBuilderTest.php +++ b/tests/FormBuilderTest.php @@ -11,7 +11,7 @@ use Illuminate\Session\Store; use Mockery as m; -class FormBuilderTest extends PHPUnit_Framework_TestCase +class FormBuilderTest extends PHPUnit\Framework\TestCase { /** * @var FormBuilder @@ -31,10 +31,10 @@ public function setUp() $request = Request::create('/foo', 'GET', [ "person" => [ "name" => "John", - "surname" => "Doe" + "surname" => "Doe", ], - "aggree" => 1, - "checkbox_array" => [1,2,3] + "agree" => 1, + "checkbox_array" => [1, 2, 3], ]); $request = Request::createFromBase($request); @@ -52,14 +52,15 @@ public function tearDown() public function testRequestValue() { - $name = $this->formBuilder->text("person[name]"); - $surname = $this->formBuilder->text("person[surname]"); + $this->formBuilder->considerRequest(); + $name = $this->formBuilder->text("person[name]", "Not John"); + $surname = $this->formBuilder->text("person[surname]", "Not Doe"); $this->assertEquals('', $name); $this->assertEquals('', $surname); - $checked = $this->formBuilder->checkbox("aggree", 1); + $checked = $this->formBuilder->checkbox("agree", 1); $unchecked = $this->formBuilder->checkbox("no_value", 1); - $this->assertEquals('', $checked); + $this->assertEquals('', $checked); $this->assertEquals('', $unchecked); $checked_array = $this->formBuilder->checkbox("checkbox_array[]", 1); @@ -67,10 +68,17 @@ public function testRequestValue() $this->assertEquals('', $checked_array); $this->assertEquals('', $unchecked_array); - $checked = $this->formBuilder->radio("aggree", 1); + $checked = $this->formBuilder->radio("agree", 1); $unchecked = $this->formBuilder->radio("no_value", 1); - $this->assertEquals('', $checked); + $this->assertEquals('', $checked); $this->assertEquals('', $unchecked); + + // now we check that Request is ignored and value take precedence + $this->formBuilder->considerRequest(false); + $name = $this->formBuilder->text("person[name]", "Not John"); + $surname = $this->formBuilder->text("person[surname]", "Not Doe"); + $this->assertEquals('', $name); + $this->assertEquals('', $surname); } public function testOpeningForm() @@ -513,7 +521,7 @@ public function testSelect() $select = $this->formBuilder->select('avc', [1 => 'Yes', 0 => 'No'], true, ['placeholder' => 'Select']); $this->assertEquals( - '', + '', $select ); } @@ -529,6 +537,58 @@ public function testSelectCollection() ); $this->assertEquals($select, ''); + + $select = $this->formBuilder->select( + 'size', + collect([ + 'Large sizes' => collect([ + 'L' => 'Large', + 'XL' => 'Extra Large', + ]), + 'S' => 'Small', + ]), + null, + [ + 'class' => 'class-name', + 'id' => 'select-id', + ] + ); + + $this->assertEquals( + $select, + '' + ); + + $select = $this->formBuilder->select( + 'size', + collect([ + 'Large sizes' => collect([ + 'L' => 'Large', + 'XL' => 'Extra Large', + ]), + 'M' => 'Medium', + 'Small sizes' => collect([ + 'S' => 'Small', + 'XS' => 'Extra Small', + ]), + ]), + null, + [], + [ + 'Large sizes' => [ + 'L' => ['disabled'] + ], + 'M' => ['disabled'], + ], + [ + 'Small sizes' => ['disabled'], + ] + ); + + $this->assertEquals( + $select, + '' + ); } public function testFormSelectRepopulation() @@ -562,7 +622,7 @@ public function testFormWithOptionalPlaceholder() ['placeholder' => 'Select One...'] ); $this->assertEquals($select, - ''); + ''); $select = $this->formBuilder->select( 'size', @@ -571,7 +631,7 @@ public function testFormWithOptionalPlaceholder() ['placeholder' => 'Select One...'] ); $this->assertEquals($select, - ''); + ''); $select = $this->formBuilder->select( 'encoded_html', @@ -580,7 +640,7 @@ public function testFormWithOptionalPlaceholder() ['placeholder' => 'Select the  '] ); $this->assertEquals($select, - '' + '' ); } @@ -704,6 +764,21 @@ public function testFormRadio() $this->assertEquals('', $form4); } + public function testFormRadioWithAttributeCastToBoolean() + { + $this->setModel(['itemA' => true, 'itemB' => false]); + + $radio1 = $this->formBuilder->radio('itemA', 1); + $radio2 = $this->formBuilder->radio('itemA', 0); + $radio3 = $this->formBuilder->radio('itemB', 1); + $radio4 = $this->formBuilder->radio('itemB', 0); + + $this->assertEquals('', $radio1); + $this->assertEquals('', $radio2); + $this->assertEquals('', $radio3); + $this->assertEquals('', $radio4); + } + public function testFormRadioRepopulation() { $this->formBuilder->setSessionStore($session = m::mock('Illuminate\Contracts\Session\Session')); @@ -787,6 +862,18 @@ public function testBooleanAttributes() $this->assertEquals('', $input); } + public function testArrayClassAttributes() + { + $input = $this->formBuilder->text('test', null, ['class' => ['class-a', 'class-b']]); + $this->assertEquals('', $input); + + $input = $this->formBuilder->text('test', null, ['class' => [ + 'class-a', + false ? 'class-b' : 'class-c' + ]]); + $this->assertEquals('', $input); + } + protected function setModel(array $data, $object = true) { if ($object) { diff --git a/tests/HtmlBuilderTest.php b/tests/HtmlBuilderTest.php index 3cb6029f..f79320af 100644 --- a/tests/HtmlBuilderTest.php +++ b/tests/HtmlBuilderTest.php @@ -7,7 +7,7 @@ use Illuminate\Routing\UrlGenerator; use Mockery as m; -class HtmlBuilderTest extends PHPUnit_Framework_TestCase +class HtmlBuilderTest extends PHPUnit\Framework\TestCase { /** @@ -151,4 +151,18 @@ public function testBooleanAttributes() $this->assertEquals('', trim($result2)); } + + public function testArrayClassAttributes() + { + $result = $this->htmlBuilder->attributes(['class' => ['class-a', 'class-b']]); + + $this->assertEquals('class="class-a class-b"', trim($result)); + + $result = $this->htmlBuilder->attributes(['class' => [ + 'class-a', + false ? 'class-b' : 'class-c' + ]]); + + $this->assertEquals('class="class-a class-c"', trim($result)); + } }