Skip to content

Commit 8381d3d

Browse files
committed
Added SubWidgets support
1 parent e32d55c commit 8381d3d

File tree

13 files changed

+202
-105
lines changed

13 files changed

+202
-105
lines changed

src/Fields/BoundField.php

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,26 @@ public function __get($name)
5656
return $this->getValue();
5757
}
5858

59+
if ($name == 'choices') {
60+
return $this->getSubWidgets();
61+
}
62+
5963
return parent::__get($name);
6064
}
6165

66+
private function getSubWidgets(array $attrs = array())
67+
{
68+
$widget = $this->field->getWidget();
69+
$attrs = $this->buildWidgetAttrs($attrs);
70+
71+
return $widget->getSubWidgets($this->html_name, $this->getValue(), $attrs);
72+
}
73+
6274
protected function asWidget($widget = null, array $attrs = array())
6375
{
6476
$widget = is_null($widget) ? $this->field->getWidget() : $widget;
6577

66-
$widget->setCssClasses($this->form->getCssClasses());
78+
$attrs = $this->buildWidgetAttrs($attrs);
6779

6880
return $widget->render($this->html_name, $this->getValue(), $attrs);
6981
}
@@ -97,4 +109,23 @@ protected function getValue()
97109

98110
return $value;
99111
}
112+
113+
private function buildWidgetAttrs(array $attrs = array())
114+
{
115+
$css_classes = implode(" ", $this->form->getCssClasses());
116+
117+
if (!empty($css_classes)) {
118+
$attrs['class'] = $css_classes;
119+
}
120+
121+
if ($this->field->isRequired()) {
122+
$attrs['required'] = 'required';
123+
}
124+
125+
if ($this->field->isDisabled()) {
126+
$attrs['disabled'] = 'disabled';
127+
}
128+
129+
return $attrs;
130+
}
100131
}

src/Fields/Field.php

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ abstract class Field
4242
*/
4343
protected $initial = null;
4444

45+
/**
46+
* @var array Array of attributes to be added to widget.
47+
*/
48+
protected $widget_attrs = array();
49+
4550
/**
4651
* @var array Array of user validators.
4752
*/
@@ -75,20 +80,17 @@ public function __construct(array $args = array())
7580
$this->disabled = array_key_exists('disabled', $args) ? $args['disabled'] : $this->disabled;
7681
$this->initial = array_key_exists('initial', $args) ? $args['initial'] : $this->initial;
7782
$this->validators = array_key_exists('validators', $args) ? $args['validators'] : $this->validators;
83+
$this->widget_attrs = array_key_exists('widget_attrs', $args) ? $args['widget_attrs'] : $this->widget_attrs;
7884
$this->error_messages = array_key_exists('error_messages', $args) ?
7985
$args['error_messages'] : $this->error_messages;
8086

8187
if (!is_null($this->widget)) {
8288
// instantiate widget class if string is passed like so: Widget::class
8389
if (is_string($this->widget)) {
84-
$widget = new $this->widget;
90+
$this->widget = new $this->widget;
8591
}
8692

87-
$widget->setRequired($this->required);
88-
$widget->setDisabled($this->disabled);
89-
$widget->setAttrs($this->widgetAttrs($widget));
90-
91-
$this->widget = $widget;
93+
$this->widget->setAttrs($this->widgetAttrs($this->widget));
9294
}
9395

9496
$this->error_messages = array_merge($this->getErrorMessages(), $this->error_messages);
@@ -241,7 +243,7 @@ public function clean($value)
241243
*/
242244
public function widgetAttrs($widget)
243245
{
244-
return array();
246+
return $this->widget_attrs;
245247
}
246248

247249
/**

src/Widgets/ChoiceWidget.php

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
abstract class ChoiceWidget extends Widget
1212
{
13-
const TEMPLATE_OPTION = "";
13+
const TEMPLATE_CHOICE = "";
1414

1515
protected $allow_multiple_selected = false;
1616
protected $input_type = null;
@@ -21,9 +21,9 @@ abstract class ChoiceWidget extends Widget
2121
/**
2222
* The constructor.
2323
*/
24-
public function __construct(array $choices = array(), array $css_classes = null, array $attrs = null)
24+
public function __construct(array $choices = array(), array $attrs = null)
2525
{
26-
parent::__construct($css_classes, $attrs);
26+
parent::__construct($attrs);
2727

2828
$this->setChoices($choices);
2929
}
@@ -36,14 +36,17 @@ public function setChoices(array $choices)
3636
public function getContext(string $name, $value, array $attrs = null)
3737
{
3838
$context = parent::getContext($name, $value, $attrs);
39-
$context["options"] = $this->renderOptions($context["name"], $context["value"], $attrs);
39+
40+
$context["options"] = implode($this->getSubWidgets($name, $value, $attrs));
4041

4142
return $context;
4243
}
4344

44-
public function renderOptions(string $name, $value, array $attrs = null)
45+
public function getSubWidgets(string $name, $value, array $attrs = null)
4546
{
46-
$options = "";
47+
$value = $this->formatValue($value);
48+
$subwidgets = array();
49+
4750
$index = 1;
4851
$has_selected = false;
4952

@@ -55,17 +58,17 @@ public function renderOptions(string $name, $value, array $attrs = null)
5558
$has_selected = true;
5659
}
5760

58-
$context = $this->getOptionContext($name, $choice_value, $choice_label, $selected, $index, $attrs);
61+
$context = $this->getSubWidgetContext($name, $choice_value, $choice_label, $selected, $index, $attrs);
5962

60-
$options .= Formatter::format(static::TEMPLATE_OPTION, $context);
63+
$subwidgets[] = Formatter::format(static::TEMPLATE_CHOICE, $context);
6164

6265
$index++;
6366
}
6467

65-
return $options;
68+
return $subwidgets;
6669
}
6770

68-
public function getOptionContext(
71+
public function getSubWidgetContext(
6972
string $name,
7073
$value,
7174
string $label,
@@ -78,7 +81,7 @@ public function getOptionContext(
7881
}
7982

8083
if ($this->option_inherits_attrs) {
81-
$attrs["id"] = $this->buildAutoId($name, $index);
84+
$attrs['id'] = $this->buildAutoId($name, $index);
8285
}
8386

8487
if ($is_selected) {
@@ -88,7 +91,7 @@ public function getOptionContext(
8891
return array(
8992
"for" => $this->buildAutoId($name, $index),
9093
"type" => $this->input_type,
91-
"name" => $name,
94+
"name" => htmlentities($name),
9295
"value" => htmlentities($value),
9396
"label" => htmlentities($label),
9497
"attrs" => Attributes::flatatt($attrs),

src/Widgets/RadioSelect.php

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
/**
3+
* Abstract class for Widgets
4+
*/
5+
namespace PHPForm\Widgets;
6+
7+
use PHPForm\Widgets\Input;
8+
9+
class RadioSelect extends ChoiceWidget
10+
{
11+
const TEMPLATE = '<div>{options}</div>';
12+
const TEMPLATE_CHOICE = '<label for="{for}">' . Input::TEMPLATE . ' {label}</label>';
13+
14+
protected $option_inherits_attrs = true;
15+
protected $selected_attribute = "checked";
16+
protected $input_type = "radio";
17+
}

src/Widgets/Select.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
class Select extends ChoiceWidget
88
{
99
const TEMPLATE = '<select name="{name}"[ {attrs}?]>{options}</select>';
10-
const TEMPLATE_OPTION = '<option value="{value}"[ {attrs}?]>{label}</option>';
10+
const TEMPLATE_CHOICE = '<option value="{value}"[ {attrs}?]>{label}</option>';
1111

1212
protected $option_inherits_attrs = false;
1313

src/Widgets/TemporalInput.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ abstract class TemporalInput extends TextInput
1313
/**
1414
* The constructor.
1515
*/
16-
public function __construct(string $format = null, array $css_classes = null, array $attrs = null)
16+
public function __construct(string $format = null, array $attrs = null)
1717
{
18-
parent::__construct($css_classes, $attrs);
18+
parent::__construct($attrs);
1919

2020
$this->format = empty($format) ? static::FORMAT : $format;
2121
}

src/Widgets/Textarea.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ class Textarea extends Widget
1111
/**
1212
* The constructor.
1313
*/
14-
public function __construct(array $css_classes = null, array $attrs = null)
14+
public function __construct(array $attrs = null)
1515
{
1616
$extra_attrs = array("cols" => 40, "rows" => 5);
1717

1818
if (!is_null($attrs)) {
1919
$extra_attrs = array_merge($extra_attrs, $attrs);
2020
}
2121

22-
parent::__construct($css_classes, $extra_attrs);
22+
parent::__construct($extra_attrs);
2323
}
2424
}

src/Widgets/Widget.php

Lines changed: 8 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,6 @@ abstract class Widget
1313
const AUTO_ID_TEMPLATE = "id_{name}[_{index}?]";
1414
const TEMPLATE = '';
1515

16-
/**
17-
* @var bool Mark the widget as required.
18-
*/
19-
protected $required = false;
20-
21-
/**
22-
* @var bool Mark the widget as disabled.
23-
*/
24-
protected $disabled = false;
25-
26-
/**
27-
* @var array Css classes to be added to widget.
28-
*/
29-
protected $css_classes = array();
30-
3116
/**
3217
* @var array Attributes to be added to the widget.
3318
*/
@@ -37,12 +22,8 @@ abstract class Widget
3722
/**
3823
* The constructor.
3924
*/
40-
public function __construct(array $css_classes = null, array $attrs = null)
25+
public function __construct(array $attrs = null)
4126
{
42-
if (!is_null($css_classes)) {
43-
$this->css_classes = $css_classes;
44-
}
45-
4627
if (!is_null($attrs)) {
4728
$this->attrs = $attrs;
4829
}
@@ -77,28 +58,15 @@ protected function getContext(string $name, $value, array $attrs = null)
7758
{
7859
$value = $this->formatValue($value);
7960
$attrs = $this->buildAttrs($attrs);
80-
$css_classes = $this->buildCssClasses();
8161

8262
if (!array_key_exists('id', $attrs)) {
8363
$attrs['id'] = $this->buildAutoId($name);
8464
}
8565

86-
if (!empty($css_classes)) {
87-
$attrs['class'] = $css_classes;
88-
}
89-
90-
if ($this->required) {
91-
$attrs['required'] = 'required';
92-
}
93-
94-
if ($this->disabled) {
95-
$attrs['disabled'] = 'disabled';
96-
}
97-
9866
return array(
9967
"name" => htmlentities($name),
10068
"attrs" => Attributes::flatatt($attrs),
101-
"value" => is_string($value) ? htmlentities($value) : $value,
69+
"value" => is_string($value) ? htmlspecialchars($value) : $value,
10270
);
10371
}
10472

@@ -138,42 +106,13 @@ private function buildCssClasses()
138106
}
139107

140108
/**
141-
* Return css classes to be added to each widget.
142-
* @return string
143-
*/
144-
public function setCssClasses(array $css_classes)
145-
{
146-
$this->css_classes = array_merge($this->css_classes, $css_classes);
147-
}
148-
149-
/**
150-
* Setter for $required attribute.
151-
*
152-
* @param bool $value Value to be setted.
153-
*/
154-
public function setRequired(bool $value)
155-
{
156-
$this->required = $value;
157-
}
158-
159-
/**
160-
* Setter for $required attribute.
161-
*
162-
* @param bool $value Value to be setted.
163-
*/
164-
public function isRequired()
165-
{
166-
return $this->required;
167-
}
168-
169-
/**
170-
* Setter for $disabled attribute.
171-
*
172-
* @param bool $value Value to be setted.
173-
*/
174-
public function setDisabled(bool $value)
109+
* Return defined subwidget.
110+
*
111+
* @return array
112+
*/
113+
public function getSubWidgets(string $name, $value, array $attrs = null)
175114
{
176-
$this->disabled = $value;
115+
return $this->widget;
177116
}
178117

179118
/**

tests/unit/Fields/BoundFieldTest.php

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
use PHPForm\Exceptions\ValidationError;
88
use PHPForm\Fields\BoundField;
99
use PHPForm\Fields\CharField;
10+
use PHPForm\Fields\ChoiceField;
11+
use PHPForm\Widgets\RadioSelect;
1012
use PHPForm\Forms\Form;
1113

1214
class BoundFieldTest extends TestCase
@@ -133,4 +135,17 @@ public function testLabelTagWithAttrs()
133135
$expected = '<label for="id_name" class="show">content</label>';
134136
$this->assertXmlStringEqualsXmlString($bound->labelTag("content", $attrs), $expected);
135137
}
138+
139+
public function testChoices()
140+
{
141+
$field = new ChoiceField(["choices" => array("option1" => "Option1", "option2" => "Option2")]);
142+
$bound = new BoundField($this->simple_form, $field, "name");
143+
144+
$expected = array(
145+
'<option value="option1">Option1</option>',
146+
'<option value="option2">Option2</option>'
147+
);
148+
149+
$this->assertEquals($expected, $bound->choices);
150+
}
136151
}

0 commit comments

Comments
 (0)