diff --git a/framework/helpers/base/Html.php b/framework/helpers/base/Html.php
index 6f30716..110dad9 100644
--- a/framework/helpers/base/Html.php
+++ b/framework/helpers/base/Html.php
@@ -10,6 +10,7 @@ namespace yii\helpers\base;
use Yii;
use yii\base\InvalidParamException;
use yii\web\Request;
+use yii\base\Model;
/**
* Html provides a set of static methods for generating commonly used HTML tags.
@@ -397,7 +398,7 @@ class Html
/**
* Generates a label tag.
* @param string $content label text. It will NOT be HTML-encoded. Therefore you can pass in HTML code
- * such as an image tag. If this is is coming from end users, you should consider [[encode()]]
+ * such as an image tag. If this is is coming from end users, you should [[encode()]]
* it to prevent XSS attacks.
* @param string $for the ID of the HTML element that this label is associated with.
* If this is null, the "for" attribute will not be generated.
@@ -609,7 +610,7 @@ class Html
* @param string $name the name attribute.
* @param boolean $checked whether the radio button should be checked.
* @param string $value the value attribute. If it is null, the value attribute will not be rendered.
- * @param array $options the tag options in terms of name-value pairs. The following options are supported:
+ * @param array $options the tag options in terms of name-value pairs. The following options are specially handled:
*
* - uncheck: string, the value associated with the uncheck state of the radio button. When this attribute
* is present, a hidden input will be generated so that if the radio button is not checked and is submitted,
@@ -639,7 +640,7 @@ class Html
* @param string $name the name attribute.
* @param boolean $checked whether the checkbox should be checked.
* @param string $value the value attribute. If it is null, the value attribute will not be rendered.
- * @param array $options the tag options in terms of name-value pairs. The following options are supported:
+ * @param array $options the tag options in terms of name-value pairs. The following options are specially handled:
*
* - uncheck: string, the value associated with the uncheck state of the checkbox. When this attribute
* is present, a hidden input will be generated so that if the checkbox is not checked and is submitted,
@@ -676,7 +677,7 @@ class Html
*
* Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in
* the labels will also be HTML-encoded.
- * @param array $options the tag options in terms of name-value pairs. The following options are supported:
+ * @param array $options the tag options in terms of name-value pairs. The following options are specially handled:
*
* - prompt: string, a prompt text to be displayed as the first option;
* - options: array, the attributes for the select option tags. The array keys must be valid option values,
@@ -716,7 +717,7 @@ class Html
*
* Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in
* the labels will also be HTML-encoded.
- * @param array $options the tag options in terms of name-value pairs. The following options are supported:
+ * @param array $options the tag options in terms of name-value pairs. The following options are specially handled:
*
* - prompt: string, a prompt text to be displayed as the first option;
* - options: array, the attributes for the select option tags. The array keys must be valid option values,
@@ -772,7 +773,7 @@ class Html
* @param array $items the data item used to generate the checkboxes.
* The array keys are the labels, while the array values are the corresponding checkbox values.
* Note that the labels will NOT be HTML-encoded, while the values will.
- * @param array $options options (name => config) for the checkbox list. The following options are supported:
+ * @param array $options options (name => config) for the checkbox list. The following options are specially handled:
*
* - unselect: string, the value that should be submitted when none of the checkboxes is selected.
* By setting this option, a hidden input will be generated.
@@ -830,7 +831,7 @@ class Html
* @param array $items the data item used to generate the radio buttons.
* The array keys are the labels, while the array values are the corresponding radio button values.
* Note that the labels will NOT be HTML-encoded, while the values will.
- * @param array $options options (name => config) for the radio button list. The following options are supported:
+ * @param array $options options (name => config) for the radio button list. The following options are specially handled:
*
* - unselect: string, the value that should be submitted when none of the radio buttons is selected.
* By setting this option, a hidden input will be generated.
@@ -876,6 +877,373 @@ class Html
}
/**
+ * Generates a label tag for the given model attribute.
+ * The label text is the label associated with the attribute, obtained via [[Model::getAttributeLabel()]].
+ * @param Model $model the model object
+ * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
+ * about attribute expression.
+ * @param array $options the tag options in terms of name-value pairs. These will be rendered as
+ * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
+ * If a value is null, the corresponding attribute will not be rendered.
+ * The following options are specially handled:
+ *
+ * - label: this specifies the label to be displayed. If this is not set, [[Model::getAttributeLabel()]]
+ * will be called to get the label for display. Note that this will NOT be [[encoded()]].
+ *
+ * @return string the generated label tag
+ */
+ public static function activeLabel($model, $attribute, $options = array())
+ {
+ $attribute = static::getAttributeName($attribute);
+ $label = isset($options['label']) ? $options['label'] : static::encode($model->getAttributeLabel($attribute));
+ $for = array_key_exists('for', $options) ? $options['for'] : static::getInputId($model, $attribute);
+ return static::label($label, $for, $options);
+ }
+
+ /**
+ * Generates an input tag for the given model attribute.
+ * This method will generate the "name" and "value" tag attributes automatically for the model attribute
+ * unless they are explicitly specified in `$options`.
+ * @param string $type the input type (e.g. 'text', 'password')
+ * @param Model $model the model object
+ * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
+ * about attribute expression.
+ * @param array $options the tag options in terms of name-value pairs. These will be rendered as
+ * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
+ * @return string the generated input tag
+ */
+ public static function activeInput($type, $model, $attribute, $options = array())
+ {
+ $name = isset($options['name']) ? $options['name'] : static::getInputName($model, $attribute);
+ $value = isset($options['value']) ? $options['value'] : static::getAttributeValue($model, $attribute);
+ if (!array_key_exists('id', $options)) {
+ $options['id'] = static::getInputId($model, $attribute);
+ }
+ return static::input($type, $name, $value, $options);
+ }
+
+ /**
+ * Generates a text input tag for the given model attribute.
+ * This method will generate the "name" and "value" tag attributes automatically for the model attribute
+ * unless they are explicitly specified in `$options`.
+ * @param Model $model the model object
+ * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
+ * about attribute expression.
+ * @param array $options the tag options in terms of name-value pairs. These will be rendered as
+ * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
+ * @return string the generated input tag
+ */
+ public static function activeTextInput($model, $attribute, $options = array())
+ {
+ return static::activeInput('text', $model, $attribute, $options);
+ }
+
+ /**
+ * Generates a hidden input tag for the given model attribute.
+ * This method will generate the "name" and "value" tag attributes automatically for the model attribute
+ * unless they are explicitly specified in `$options`.
+ * @param Model $model the model object
+ * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
+ * about attribute expression.
+ * @param array $options the tag options in terms of name-value pairs. These will be rendered as
+ * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
+ * @return string the generated input tag
+ */
+ public static function activeHiddenInput($model, $attribute, $options = array())
+ {
+ return static::activeInput('hidden', $model, $attribute, $options);
+ }
+
+ /**
+ * Generates a password input tag for the given model attribute.
+ * This method will generate the "name" and "value" tag attributes automatically for the model attribute
+ * unless they are explicitly specified in `$options`.
+ * @param Model $model the model object
+ * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
+ * about attribute expression.
+ * @param array $options the tag options in terms of name-value pairs. These will be rendered as
+ * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
+ * @return string the generated input tag
+ */
+ public static function activePasswordInput($model, $attribute, $options = array())
+ {
+ return static::activeInput('password', $model, $attribute, $options);
+ }
+
+ /**
+ * Generates a file input tag for the given model attribute.
+ * This method will generate the "name" and "value" tag attributes automatically for the model attribute
+ * unless they are explicitly specified in `$options`.
+ * @param Model $model the model object
+ * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
+ * about attribute expression.
+ * @param array $options the tag options in terms of name-value pairs. These will be rendered as
+ * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
+ * @return string the generated input tag
+ */
+ public static function activeFileInput($model, $attribute, $options = array())
+ {
+ return static::activeInput('file', $model, $attribute, $options);
+ }
+
+ /**
+ * Generates a textarea tag for the given model attribute.
+ * The model attribute value will be used as the content in the textarea.
+ * @param Model $model the model object
+ * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
+ * about attribute expression.
+ * @param array $options the tag options in terms of name-value pairs. These will be rendered as
+ * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
+ * @return string the generated textarea tag
+ */
+ public static function activeTextarea($model, $attribute, $options = array())
+ {
+ $name = static::getInputName($model, $attribute);
+ $value = static::getAttributeValue($model, $attribute);
+ if (!array_key_exists('id', $options)) {
+ $options['id'] = static::getInputId($model, $attribute);
+ }
+ return static::textarea($name, $value, $options);
+ }
+
+ /**
+ * Generates a radio button tag for the given model attribute.
+ * This method will generate the "name" tag attribute automatically unless it is explicitly specified in `$options`.
+ * This method will generate the "checked" tag attribute according to the model attribute value.
+ * @param Model $model the model object
+ * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
+ * about attribute expression.
+ * @param string $value the value tag attribute. If it is null, the value attribute will not be rendered.
+ * @param array $options the tag options in terms of name-value pairs. The following options are specially handled:
+ *
+ * - uncheck: string, the value associated with the uncheck state of the radio button. If not set,
+ * it will take the default value '0'. This method will render a hidden input so that if the radio button
+ * is not checked and is submitted, the value of this attribute will still be submitted to the server
+ * via the hidden input.
+ *
+ * The rest of the options will be rendered as the attributes of the resulting tag. The values will
+ * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
+ *
+ * @return string the generated radio button tag
+ */
+ public static function activeRadio($model, $attribute, $value = '1', $options = array())
+ {
+ $name = isset($options['name']) ? $options['name'] : static::getInputName($model, $attribute);
+ $checked = static::getAttributeValue($model, $attribute);
+ if (!array_key_exists('uncheck', $options)) {
+ $options['unchecked'] = '0';
+ }
+ if (!array_key_exists('id', $options)) {
+ $options['id'] = static::getInputId($model, $attribute);
+ }
+ return static::radio($name, $checked, $value, $options);
+ }
+
+ /**
+ * Generates a checkbox tag for the given model attribute.
+ * This method will generate the "name" tag attribute automatically unless it is explicitly specified in `$options`.
+ * This method will generate the "checked" tag attribute according to the model attribute value.
+ * @param Model $model the model object
+ * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
+ * about attribute expression.
+ * @param string $value the value tag attribute. If it is null, the value attribute will not be rendered.
+ * @param array $options the tag options in terms of name-value pairs. The following options are specially handled:
+ *
+ * - uncheck: string, the value associated with the uncheck state of the radio button. If not set,
+ * it will take the default value '0'. This method will render a hidden input so that if the radio button
+ * is not checked and is submitted, the value of this attribute will still be submitted to the server
+ * via the hidden input.
+ *
+ * The rest of the options will be rendered as the attributes of the resulting tag. The values will
+ * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
+ *
+ * @return string the generated checkbox tag
+ */
+ public static function activeCheckbox($model, $attribute, $value = '1', $options = array())
+ {
+ $name = isset($options['name']) ? $options['name'] : static::getInputName($model, $attribute);
+ $checked = static::getAttributeValue($model, $attribute);
+ if (!array_key_exists('uncheck', $options)) {
+ $options['unchecked'] = '0';
+ }
+ if (!array_key_exists('id', $options)) {
+ $options['id'] = static::getInputId($model, $attribute);
+ }
+ return static::checkbox($name, $checked, $value, $options);
+ }
+
+ /**
+ * Generates a drop-down list for the given model attribute.
+ * The selection of the drop-down list is taken from the value of the model attribute.
+ * @param Model $model the model object
+ * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
+ * about attribute expression.
+ * @param array $items the option data items. The array keys are option values, and the array values
+ * are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too).
+ * For each sub-array, an option group will be generated whose label is the key associated with the sub-array.
+ * If you have a list of data models, you may convert them into the format described above using
+ * [[\yii\helpers\ArrayHelper::map()]].
+ *
+ * Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in
+ * the labels will also be HTML-encoded.
+ * @param array $options the tag options in terms of name-value pairs. The following options are specially handled:
+ *
+ * - prompt: string, a prompt text to be displayed as the first option;
+ * - options: array, the attributes for the select option tags. The array keys must be valid option values,
+ * and the array values are the extra attributes for the corresponding option tags. For example,
+ *
+ * ~~~
+ * array(
+ * 'value1' => array('disabled' => true),
+ * 'value2' => array('label' => 'value 2'),
+ * );
+ * ~~~
+ *
+ * - groups: array, the attributes for the optgroup tags. The structure of this is similar to that of 'options',
+ * except that the array keys represent the optgroup labels specified in $items.
+ *
+ * The rest of the options will be rendered as the attributes of the resulting tag. The values will
+ * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
+ *
+ * @return string the generated drop-down list tag
+ */
+ public static function activeDropDownList($model, $attribute, $items, $options = array())
+ {
+ $name = isset($options['name']) ? $options['name'] : static::getInputName($model, $attribute);
+ $checked = static::getAttributeValue($model, $attribute);
+ if (!array_key_exists('id', $options)) {
+ $options['id'] = static::getInputId($model, $attribute);
+ }
+ return static::dropDownList($name, $checked, $items, $options);
+ }
+
+ /**
+ * Generates a list box.
+ * The selection of the list box is taken from the value of the model attribute.
+ * @param Model $model the model object
+ * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
+ * about attribute expression.
+ * @param array $items the option data items. The array keys are option values, and the array values
+ * are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too).
+ * For each sub-array, an option group will be generated whose label is the key associated with the sub-array.
+ * If you have a list of data models, you may convert them into the format described above using
+ * [[\yii\helpers\ArrayHelper::map()]].
+ *
+ * Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in
+ * the labels will also be HTML-encoded.
+ * @param array $options the tag options in terms of name-value pairs. The following options are specially handled:
+ *
+ * - prompt: string, a prompt text to be displayed as the first option;
+ * - options: array, the attributes for the select option tags. The array keys must be valid option values,
+ * and the array values are the extra attributes for the corresponding option tags. For example,
+ *
+ * ~~~
+ * array(
+ * 'value1' => array('disabled' => true),
+ * 'value2' => array('label' => 'value 2'),
+ * );
+ * ~~~
+ *
+ * - groups: array, the attributes for the optgroup tags. The structure of this is similar to that of 'options',
+ * except that the array keys represent the optgroup labels specified in $items.
+ * - unselect: string, the value that will be submitted when no option is selected.
+ * When this attribute is set, a hidden field will be generated so that if no option is selected in multiple
+ * mode, we can still obtain the posted unselect value.
+ *
+ * The rest of the options will be rendered as the attributes of the resulting tag. The values will
+ * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
+ *
+ * @return string the generated list box tag
+ */
+ public static function activeListBox($model, $attribute, $items, $options = array())
+ {
+ $name = isset($options['name']) ? $options['name'] : static::getInputName($model, $attribute);
+ $checked = static::getAttributeValue($model, $attribute);
+ if (!array_key_exists('unselect', $options)) {
+ $options['unselect'] = '0';
+ }
+ if (!array_key_exists('id', $options)) {
+ $options['id'] = static::getInputId($model, $attribute);
+ }
+ return static::listBox($name, $checked, $items, $options);
+ }
+
+ /**
+ * Generates a list of checkboxes.
+ * A checkbox list allows multiple selection, like [[listBox()]].
+ * As a result, the corresponding submitted value is an array.
+ * The selection of the checkbox list is taken from the value of the model attribute.
+ * @param Model $model the model object
+ * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
+ * about attribute expression.
+ * @param array $items the data item used to generate the checkboxes.
+ * The array keys are the labels, while the array values are the corresponding checkbox values.
+ * Note that the labels will NOT be HTML-encoded, while the values will.
+ * @param array $options options (name => config) for the checkbox list. The following options are specially handled:
+ *
+ * - unselect: string, the value that should be submitted when none of the checkboxes is selected.
+ * By setting this option, a hidden input will be generated.
+ * - separator: string, the HTML code that separates items.
+ * - item: callable, a callback that can be used to customize the generation of the HTML code
+ * corresponding to a single item in $items. The signature of this callback must be:
+ *
+ * ~~~
+ * function ($index, $label, $name, $checked, $value)
+ * ~~~
+ *
+ * where $index is the zero-based index of the checkbox in the whole list; $label
+ * is the label for the checkbox; and $name, $value and $checked represent the name,
+ * value and the checked status of the checkbox input.
+ * @return string the generated checkbox list
+ */
+ public static function activeCheckboxList($model, $attribute, $items, $options = array())
+ {
+ $name = isset($options['name']) ? $options['name'] : static::getInputName($model, $attribute);
+ $checked = static::getAttributeValue($model, $attribute);
+ if (!array_key_exists('unselect', $options)) {
+ $options['unselect'] = '0';
+ }
+ return static::checkboxList($name, $checked, $items, $options);
+ }
+
+ /**
+ * Generates a list of radio buttons.
+ * A radio button list is like a checkbox list, except that it only allows single selection.
+ * The selection of the radio buttons is taken from the value of the model attribute.
+ * @param Model $model the model object
+ * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for the format
+ * about attribute expression.
+ * @param array $items the data item used to generate the radio buttons.
+ * The array keys are the labels, while the array values are the corresponding radio button values.
+ * Note that the labels will NOT be HTML-encoded, while the values will.
+ * @param array $options options (name => config) for the radio button list. The following options are specially handled:
+ *
+ * - unselect: string, the value that should be submitted when none of the radio buttons is selected.
+ * By setting this option, a hidden input will be generated.
+ * - separator: string, the HTML code that separates items.
+ * - item: callable, a callback that can be used to customize the generation of the HTML code
+ * corresponding to a single item in $items. The signature of this callback must be:
+ *
+ * ~~~
+ * function ($index, $label, $name, $checked, $value)
+ * ~~~
+ *
+ * where $index is the zero-based index of the radio button in the whole list; $label
+ * is the label for the radio button; and $name, $value and $checked represent the name,
+ * value and the checked status of the radio button input.
+ * @return string the generated radio button list
+ */
+ public static function activeRadioList($model, $attribute, $items, $options = array())
+ {
+ $name = isset($options['name']) ? $options['name'] : static::getInputName($model, $attribute);
+ $checked = static::getAttributeValue($model, $attribute);
+ if (!array_key_exists('unselect', $options)) {
+ $options['unselect'] = '0';
+ }
+ return static::radioList($name, $checked, $items, $options);
+ }
+
+ /**
* Renders the option tags that can be used by [[dropDownList()]] and [[listBox()]].
* @param string|array $selection the selected value(s). This can be either a string for single selection
* or an array for multiple selections.
@@ -995,4 +1363,113 @@ class Html
return Yii::getAlias($url);
}
}
+
+ /**
+ * Returns the real attribute name from the given attribute expression.
+ *
+ * An attribute expression is an attribute name prefixed and/or suffixed with array indexes.
+ * It is mainly used in tabular data input and/or input of array type. Below are some examples:
+ *
+ * - `[0]content` is used in tabular data input to represent the "content" attribute
+ * for the first model in tabular input;
+ * - `dates[0]` represents the first array element of the "dates" attribute;
+ * - `[0]dates[0]` represents the first array element of the "dates" attribute
+ * for the first model in tabular input.
+ *
+ * If `$attribute` has neither prefix nor suffix, it will be returned back without change.
+ * @param string $attribute the attribute name or expression
+ * @return string the attribute name without prefix and suffix.
+ * @throws InvalidParamException if the attribute name contains non-word characters.
+ */
+ public static function getAttributeName($attribute)
+ {
+ if (preg_match('/(^|.*\])(\w+)(\[.*|$)/', $attribute, $matches)) {
+ return $matches[2];
+ } else {
+ throw new InvalidParamException('Attribute name must contain word characters only.');
+ }
+ }
+
+ /**
+ * Returns the value of the specified attribute name or expression.
+ *
+ * For an attribute expression like `[0]dates[0]`, this method will return the value of `$model->dates[0]`.
+ * See [[getAttributeName()]] for more details about attribute expression.
+ *
+ * @param Model $model the model object
+ * @param string $attribute the attribute name or expression
+ * @return mixed the corresponding attribute value
+ * @throws InvalidParamException if the attribute name contains non-word characters.
+ */
+ public static function getAttributeValue($model, $attribute)
+ {
+ if (!preg_match('/(^|.*\])(\w+)(\[.*|$)/', $attribute, $matches)) {
+ throw new InvalidParamException('Attribute name must contain word characters only.');
+ }
+ $attribute = $matches[2];
+ $index = $matches[3];
+ if ($index === '') {
+ return $model->$attribute;
+ } else {
+ $value = $model->$attribute;
+ foreach (explode('][', trim($index, '[]')) as $id) {
+ if ((is_array($value) || $value instanceof \ArrayAccess) && isset($value[$id])) {
+ $value = $value[$id];
+ } else {
+ return null;
+ }
+ }
+ return $value;
+ }
+ }
+
+ /**
+ * Generates an appropriate input name for the specified attribute name or expression.
+ *
+ * This method generates a name that can be used as the input name to collect user input
+ * for the specified attribute. The name is generated according to the [[Model::formName|form name]]
+ * of the model and the given attribute name. For example, if the form name of the `Post` model
+ * is `Post`, then the input name generated for the `content` attribute would be `Post[content]`.
+ *
+ * See [[getAttributeName()]] for explanation of attribute expression.
+ *
+ * @param Model $model the model object
+ * @param string $attribute the attribute name or expression
+ * @return string the generated input name
+ * @throws InvalidParamException if the attribute name contains non-word characters.
+ */
+ public static function getInputName($model, $attribute)
+ {
+ $formName = $model->formName();
+ if (!preg_match('/(^|.*\])(\w+)(\[.*|$)/', $attribute, $matches)) {
+ throw new InvalidParamException('Attribute name must contain word characters only.');
+ }
+ $prefix = $matches[1];
+ $attribute = $matches[2];
+ $suffix = $matches[3];
+ if ($formName === '' && $prefix === '') {
+ return $attribute . $suffix;
+ } elseif ($formName !== '') {
+ return $formName . $prefix . "[$attribute]" . $suffix;
+ } else {
+ throw new InvalidParamException(get_class($model) . '::formName() cannot be empty for tabular inputs.');
+ }
+ }
+
+ /**
+ * Generates an appropriate input ID for the specified attribute name or expression.
+ *
+ * This method converts the result [[getInputName()]] into a valid input ID.
+ * For example, [[getInputName()]] returns `Post[content]`, this method will return `Post-method`.
+ * @param Model $model the model object
+ * @param string $attribute the attribute name or expression. See [[getAttributeName()]] for explanation of attribute expression.
+ * @return string the generated input ID
+ * @throws InvalidParamException if the attribute name contains non-word characters.
+ */
+ public static function getInputId($model, $attribute)
+ {
+ $name = static::getInputName($model, $attribute);
+ return str_replace(array('[]', '][', '[', ']', ' '), array('', '-', '-', '', '-'), $name);
+ }
+
}
diff --git a/framework/widgets/ActiveField.php b/framework/widgets/ActiveField.php
new file mode 100644
index 0000000..50b9619
--- /dev/null
+++ b/framework/widgets/ActiveField.php
@@ -0,0 +1,321 @@
+
+ * @since 2.0
+ */
+class ActiveField extends Component
+{
+ /**
+ * @var ActiveForm
+ */
+ public $form;
+ /**
+ * @var \yii\base\Model
+ */
+ public $model;
+ /**
+ * @var string
+ */
+ public $attribute;
+ /**
+ * @var array
+ */
+ public $options;
+
+ public function begin()
+ {
+ return Html::beginTag('div', $this->options);
+ }
+
+ public function end()
+ {
+ return Html::endTag('div');
+ }
+
+ public function error($options = array())
+ {
+ if (empty($options)) {
+ $options = $this->form->errorOptions;
+ }
+ $attribute = Html::getAttributeName($this->attribute);
+ $tag = isset($options['tag']) ? $options['tag'] : 'div';
+ unset($options['tag']);
+ $error = $this->model->getFirstError($attribute);
+ return Html::tag($tag, Html::encode($error), $options);
+ }
+
+ public function label($options = array())
+ {
+ if (empty($options)) {
+ $options = $this->form->labelOptions;
+ }
+ return Html::activeLabel($this->model, $this->attribute, $options);
+ }
+
+ /**
+ * Generates an input tag for the given model attribute.
+ * @param string $type the input type (e.g. 'text', 'password')
+ * @param array $options the tag options in terms of name-value pairs. These will be rendered as
+ * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
+ * @return string the generated input tag
+ */
+ public function input($type, $options = array())
+ {
+ return Html::activeInput($type, $this->model, $this->attribute, $options);
+ }
+
+ /**
+ * Generates a text input tag for the given model attribute.
+ * This method will generate the "name" and "value" tag attributes automatically for the model attribute
+ * unless they are explicitly specified in `$options`.
+ * @param array $options the tag options in terms of name-value pairs. These will be rendered as
+ * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
+ * @return string the generated input tag
+ */
+ public function textInput($options = array())
+ {
+ return Html::activeTextInput($this->model, $this->attribute, $options);
+ }
+
+ /**
+ * Generates a hidden input tag for the given model attribute.
+ * This method will generate the "name" and "value" tag attributes automatically for the model attribute
+ * unless they are explicitly specified in `$options`.
+ * @param array $options the tag options in terms of name-value pairs. These will be rendered as
+ * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
+ * @return string the generated input tag
+ */
+ public function hiddenInput($options = array())
+ {
+ return Html::activeHiddenInput($this->model, $this->attribute, $options);
+ }
+
+ /**
+ * Generates a password input tag for the given model attribute.
+ * This method will generate the "name" and "value" tag attributes automatically for the model attribute
+ * unless they are explicitly specified in `$options`.
+ * @param array $options the tag options in terms of name-value pairs. These will be rendered as
+ * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
+ * @return string the generated input tag
+ */
+ public function passwordInput($options = array())
+ {
+ return Html::activeHiddenInput($this->model, $this->attribute, $options);
+ }
+
+ /**
+ * Generates a file input tag for the given model attribute.
+ * This method will generate the "name" and "value" tag attributes automatically for the model attribute
+ * unless they are explicitly specified in `$options`.
+ * @param array $options the tag options in terms of name-value pairs. These will be rendered as
+ * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
+ * @return string the generated input tag
+ */
+ public function fileInput($options = array())
+ {
+ return Html::activeFileInput($this->model, $this->attribute, $options);
+ }
+
+ /**
+ * Generates a textarea tag for the given model attribute.
+ * The model attribute value will be used as the content in the textarea.
+ * @param array $options the tag options in terms of name-value pairs. These will be rendered as
+ * the attributes of the resulting tag. The values will be HTML-encoded using [[encode()]].
+ * @return string the generated textarea tag
+ */
+ public function textarea($options = array())
+ {
+ return Html::activeTextarea($this->model, $this->attribute, $options);
+ }
+
+ /**
+ * Generates a radio button tag for the given model attribute.
+ * This method will generate the "name" tag attribute automatically unless it is explicitly specified in `$options`.
+ * This method will generate the "checked" tag attribute according to the model attribute value.
+ * @param string $value the value tag attribute. If it is null, the value attribute will not be rendered.
+ * @param array $options the tag options in terms of name-value pairs. The following options are specially handled:
+ *
+ * - uncheck: string, the value associated with the uncheck state of the radio button. If not set,
+ * it will take the default value '0'. This method will render a hidden input so that if the radio button
+ * is not checked and is submitted, the value of this attribute will still be submitted to the server
+ * via the hidden input.
+ *
+ * The rest of the options will be rendered as the attributes of the resulting tag. The values will
+ * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
+ *
+ * @return string the generated radio button tag
+ */
+ public function radio($value = '1', $options = array())
+ {
+ return Html::activeRadio($this->model, $this->attribute, $value, $options);
+ }
+
+ /**
+ * Generates a checkbox tag for the given model attribute.
+ * This method will generate the "name" tag attribute automatically unless it is explicitly specified in `$options`.
+ * This method will generate the "checked" tag attribute according to the model attribute value.
+ * @param string $value the value tag attribute. If it is null, the value attribute will not be rendered.
+ * @param array $options the tag options in terms of name-value pairs. The following options are specially handled:
+ *
+ * - uncheck: string, the value associated with the uncheck state of the radio button. If not set,
+ * it will take the default value '0'. This method will render a hidden input so that if the radio button
+ * is not checked and is submitted, the value of this attribute will still be submitted to the server
+ * via the hidden input.
+ *
+ * The rest of the options will be rendered as the attributes of the resulting tag. The values will
+ * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
+ *
+ * @return string the generated checkbox tag
+ */
+ public function checkbox($value = '1', $options = array())
+ {
+ return Html::activeCheckbox($this->model, $this->attribute, $value, $options);
+ }
+
+ /**
+ * Generates a drop-down list for the given model attribute.
+ * The selection of the drop-down list is taken from the value of the model attribute.
+ * @param array $items the option data items. The array keys are option values, and the array values
+ * are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too).
+ * For each sub-array, an option group will be generated whose label is the key associated with the sub-array.
+ * If you have a list of data models, you may convert them into the format described above using
+ * [[\yii\helpers\ArrayHelper::map()]].
+ *
+ * Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in
+ * the labels will also be HTML-encoded.
+ * @param array $options the tag options in terms of name-value pairs. The following options are specially handled:
+ *
+ * - prompt: string, a prompt text to be displayed as the first option;
+ * - options: array, the attributes for the select option tags. The array keys must be valid option values,
+ * and the array values are the extra attributes for the corresponding option tags. For example,
+ *
+ * ~~~
+ * array(
+ * 'value1' => array('disabled' => true),
+ * 'value2' => array('label' => 'value 2'),
+ * );
+ * ~~~
+ *
+ * - groups: array, the attributes for the optgroup tags. The structure of this is similar to that of 'options',
+ * except that the array keys represent the optgroup labels specified in $items.
+ *
+ * The rest of the options will be rendered as the attributes of the resulting tag. The values will
+ * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
+ *
+ * @return string the generated drop-down list tag
+ */
+ public function DropDownList($items, $options = array())
+ {
+ return Html::activeDropDownList($this->model, $this->attribute, $items, $options);
+ }
+
+ /**
+ * Generates a list box.
+ * The selection of the list box is taken from the value of the model attribute.
+ * @param array $items the option data items. The array keys are option values, and the array values
+ * are the corresponding option labels. The array can also be nested (i.e. some array values are arrays too).
+ * For each sub-array, an option group will be generated whose label is the key associated with the sub-array.
+ * If you have a list of data models, you may convert them into the format described above using
+ * [[\yii\helpers\ArrayHelper::map()]].
+ *
+ * Note, the values and labels will be automatically HTML-encoded by this method, and the blank spaces in
+ * the labels will also be HTML-encoded.
+ * @param array $options the tag options in terms of name-value pairs. The following options are specially handled:
+ *
+ * - prompt: string, a prompt text to be displayed as the first option;
+ * - options: array, the attributes for the select option tags. The array keys must be valid option values,
+ * and the array values are the extra attributes for the corresponding option tags. For example,
+ *
+ * ~~~
+ * array(
+ * 'value1' => array('disabled' => true),
+ * 'value2' => array('label' => 'value 2'),
+ * );
+ * ~~~
+ *
+ * - groups: array, the attributes for the optgroup tags. The structure of this is similar to that of 'options',
+ * except that the array keys represent the optgroup labels specified in $items.
+ * - unselect: string, the value that will be submitted when no option is selected.
+ * When this attribute is set, a hidden field will be generated so that if no option is selected in multiple
+ * mode, we can still obtain the posted unselect value.
+ *
+ * The rest of the options will be rendered as the attributes of the resulting tag. The values will
+ * be HTML-encoded using [[encode()]]. If a value is null, the corresponding attribute will not be rendered.
+ *
+ * @return string the generated list box tag
+ */
+ public function listBox($items, $options = array())
+ {
+ return Html::activeListBox($this->model, $this->attribute, $items, $options);
+ }
+
+ /**
+ * Generates a list of checkboxes.
+ * A checkbox list allows multiple selection, like [[listBox()]].
+ * As a result, the corresponding submitted value is an array.
+ * The selection of the checkbox list is taken from the value of the model attribute.
+ * @param array $items the data item used to generate the checkboxes.
+ * The array keys are the labels, while the array values are the corresponding checkbox values.
+ * Note that the labels will NOT be HTML-encoded, while the values will.
+ * @param array $options options (name => config) for the checkbox list. The following options are specially handled:
+ *
+ * - unselect: string, the value that should be submitted when none of the checkboxes is selected.
+ * By setting this option, a hidden input will be generated.
+ * - separator: string, the HTML code that separates items.
+ * - item: callable, a callback that can be used to customize the generation of the HTML code
+ * corresponding to a single item in $items. The signature of this callback must be:
+ *
+ * ~~~
+ * function ($index, $label, $name, $checked, $value)
+ * ~~~
+ *
+ * where $index is the zero-based index of the checkbox in the whole list; $label
+ * is the label for the checkbox; and $name, $value and $checked represent the name,
+ * value and the checked status of the checkbox input.
+ * @return string the generated checkbox list
+ */
+ public function checkboxList($items, $options = array())
+ {
+ return Html::activeCheckboxList($this->model, $this->attribute, $items, $options);
+ }
+
+ /**
+ * Generates a list of radio buttons.
+ * A radio button list is like a checkbox list, except that it only allows single selection.
+ * The selection of the radio buttons is taken from the value of the model attribute.
+ * @param array $items the data item used to generate the radio buttons.
+ * The array keys are the labels, while the array values are the corresponding radio button values.
+ * Note that the labels will NOT be HTML-encoded, while the values will.
+ * @param array $options options (name => config) for the radio button list. The following options are specially handled:
+ *
+ * - unselect: string, the value that should be submitted when none of the radio buttons is selected.
+ * By setting this option, a hidden input will be generated.
+ * - separator: string, the HTML code that separates items.
+ * - item: callable, a callback that can be used to customize the generation of the HTML code
+ * corresponding to a single item in $items. The signature of this callback must be:
+ *
+ * ~~~
+ * function ($index, $label, $name, $checked, $value)
+ * ~~~
+ *
+ * where $index is the zero-based index of the radio button in the whole list; $label
+ * is the label for the radio button; and $name, $value and $checked represent the name,
+ * value and the checked status of the radio button input.
+ * @return string the generated radio button list
+ */
+ public function radioList($items, $options = array())
+ {
+ return Html::activeRadioList($this->model, $this->attribute, $items, $options);
+ }
+}
\ No newline at end of file
diff --git a/framework/widgets/ActiveForm.php b/framework/widgets/ActiveForm.php
index 79331e5..7bb790f 100644
--- a/framework/widgets/ActiveForm.php
+++ b/framework/widgets/ActiveForm.php
@@ -8,6 +8,7 @@
namespace yii\widgets;
use Yii;
+use yii\base\InvalidCallException;
use yii\base\InvalidParamException;
use yii\base\Widget;
use yii\base\Model;
@@ -31,25 +32,26 @@ class ActiveForm extends Widget
* Defaults to 'post'.
*/
public $method = 'post';
+ public $options = array();
+ public $errorOptions = array('tag' => 'div', 'class' => 'yii-error-message');
+ public $labelOptions = array('class' => 'yii-input-label');
/**
* @var string the default CSS class for the error summary container.
* @see errorSummary()
*/
- public $errorSummaryClass = 'yii-error-summary';
- public $errorMessageClass = 'yii-error-message';
+ public $errorSummaryCssClass = 'yii-error-summary';
/**
* @var string the default CSS class that indicates an input has error.
*/
- public $errorClass = 'yii-error';
+ public $errorCssClass = 'yii-error';
/**
* @var string the default CSS class that indicates an input validated successfully.
*/
- public $successClass = 'yii-success';
-
+ public $successCssClass = 'yii-success';
/**
* @var string the default CSS class that indicates an input is currently being validated.
*/
- public $validatingClass = 'yii-validating';
+ public $validatingCssClass = 'yii-validating';
/**
* @var boolean whether to enable client-side data validation. Defaults to false.
* When this property is set true, client-side validation will be performed by validators
@@ -57,9 +59,7 @@ class ActiveForm extends Widget
*/
public $enableClientValidation = false;
- public $options = array();
-
-
+ public $fieldClass = 'yii\widgets\ActiveField';
/**
* Initializes the widget.
* This renders the form open tag.
@@ -108,9 +108,9 @@ class ActiveForm extends Widget
unset($options['showAll'], $options['header'], $options['footer'], $options['container']);
if (!isset($options['class'])) {
- $options['class'] = $this->errorSummaryClass;
+ $options['class'] = $this->errorSummaryCssClass;
} else {
- $options['class'] .= ' ' . $this->errorSummaryClass;
+ $options['class'] .= ' ' . $this->errorSummaryCssClass;
}
if ($lines !== array()) {
@@ -124,209 +124,30 @@ class ActiveForm extends Widget
}
/**
- * @param Model $model
- * @param string $attribute
- * @param array $options
- * @return string
- */
- public function error($model, $attribute, $options = array())
- {
- $attribute = $this->getAttributeName($attribute);
- $tag = isset($options['tag']) ? $options['tag'] : 'div';
- unset($options['tag']);
- $error = $model->getFirstError($attribute);
- return Html::tag($tag, Html::encode($error), $options);
- }
-
- /**
- * @param Model $model
- * @param string $attribute
- * @param array $options
- * @return string
+ * @var ActiveField[]
*/
- public function label($model, $attribute, $options = array())
- {
- $attribute = $this->getAttributeName($attribute);
- $label = isset($options['label']) ? $options['label'] : Html::encode($model->getAttributeLabel($attribute));
- $for = array_key_exists('for', $options) ? $options['for'] : $this->getInputId($model, $attribute);
- return Html::label($label, $for, $options);
- }
+ private $_fieldStack = array();
- /**
- * @param string $type
- * @param Model $model
- * @param string $attribute
- * @param array $options
- *
- * @return string
- */
- public function input($type, $model, $attribute, $options = array())
+ public function beginField($model, $attribute, $options = array())
{
- $value = $this->getAttributeValue($model, $attribute);
- $name = $this->getInputName($model, $attribute);
- if (!array_key_exists('id', $options)) {
- $options['id'] = $this->getInputId($model, $attribute);
- }
- return Html::input($type, $name, $value, $options);
- }
-
- public function textInput($model, $attribute, $options = array())
- {
- return $this->input('text', $model, $attribute, $options);
- }
-
- public function hiddenInput($model, $attribute, $options = array())
- {
- return $this->input('hidden', $model, $attribute, $options);
- }
-
- public function passwordInput($model, $attribute, $options = array())
- {
- return $this->input('password', $model, $attribute, $options);
- }
-
- public function fileInput($model, $attribute, $options = array())
- {
- return $this->input('file', $model, $attribute, $options);
- }
-
- public function textarea($model, $attribute, $options = array())
- {
- $value = $this->getAttributeValue($model, $attribute);
- $name = $this->getInputName($model, $attribute);
- if (!array_key_exists('id', $options)) {
- $options['id'] = $this->getInputId($model, $attribute);
- }
- return Html::textarea($name, $value, $options);
- }
-
- public function radio($model, $attribute, $value = '1', $options = array())
- {
- $checked = $this->getAttributeValue($model, $attribute);
- $name = $this->getInputName($model, $attribute);
- if (!array_key_exists('uncheck', $options)) {
- $options['unchecked'] = '0';
- }
- if (!array_key_exists('id', $options)) {
- $options['id'] = $this->getInputId($model, $attribute);
- }
- return Html::radio($name, $checked, $value, $options);
+ $field = Yii::createObject(array(
+ 'class' => $this->fieldClass,
+ 'model' => $model,
+ 'attribute' => $attribute,
+ 'form' => $this,
+ 'options' => $options,
+ ));
+ echo $field->begin();
+ return $this->_fieldStack[] = $field;
}
- public function checkbox($model, $attribute, $value = '1', $options = array())
+ public function endField()
{
- $checked = $this->getAttributeValue($model, $attribute);
- $name = $this->getInputName($model, $attribute);
- if (!array_key_exists('uncheck', $options)) {
- $options['unchecked'] = '0';
- }
- if (!array_key_exists('id', $options)) {
- $options['id'] = $this->getInputId($model, $attribute);
- }
- return Html::checkbox($name, $checked, $value, $options);
- }
-
- public function dropDownList($model, $attribute, $items, $options = array())
- {
- $checked = $this->getAttributeValue($model, $attribute);
- $name = $this->getInputName($model, $attribute);
- if (!array_key_exists('id', $options)) {
- $options['id'] = $this->getInputId($model, $attribute);
- }
- return Html::dropDownList($name, $checked, $items, $options);
- }
-
- public function listBox($model, $attribute, $items, $options = array())
- {
- $checked = $this->getAttributeValue($model, $attribute);
- $name = $this->getInputName($model, $attribute);
- if (!array_key_exists('unselect', $options)) {
- $options['unselect'] = '0';
- }
- if (!array_key_exists('id', $options)) {
- $options['id'] = $this->getInputId($model, $attribute);
- }
- return Html::listBox($name, $checked, $items, $options);
- }
-
- public function checkboxList($model, $attribute, $items, $options = array())
- {
- $checked = $this->getAttributeValue($model, $attribute);
- $name = $this->getInputName($model, $attribute);
- if (!array_key_exists('unselect', $options)) {
- $options['unselect'] = '0';
- }
- return Html::checkboxList($name, $checked, $items, $options);
- }
-
- public function radioList($model, $attribute, $items, $options = array())
- {
- $checked = $this->getAttributeValue($model, $attribute);
- $name = $this->getInputName($model, $attribute);
- if (!array_key_exists('unselect', $options)) {
- $options['unselect'] = '0';
- }
- return Html::radioList($name, $checked, $items, $options);
- }
-
- public function getAttributeValue($model, $attribute)
- {
- if (!preg_match('/(^|.*\])(\w+)(\[.*|$)/', $attribute, $matches)) {
- throw new InvalidParamException('Attribute name must contain word characters only.');
- }
- $attribute = $matches[2];
- $index = $matches[3];
- if ($index === '') {
- return $model->$attribute;
+ if ($this->_fieldStack !== array()) {
+ $field = array_pop($this->_fieldStack);
+ echo $field->end();
} else {
- $value = $model->$attribute;
- foreach (explode('][', trim($index, '[]')) as $id) {
- if ((is_array($value) || $value instanceof \ArrayAccess) && isset($value[$id])) {
- $value = $value[$id];
- } else {
- return null;
- }
- }
- return $value;
+ throw new InvalidCallException('The "beginField" and "endField" calls are not matching.');
}
}
-
- public function getAttributeName($attribute)
- {
- if (preg_match('/(^|.*\])(\w+)(\[.*|$)/', $attribute, $matches)) {
- return $matches[2];
- } else {
- throw new InvalidParamException('Attribute name must contain word characters only.');
- }
- }
-
- /**
- * @param Model $model
- * @param string $attribute
- * @return string
- * @throws \yii\base\InvalidParamException
- */
- public static function getInputName($model, $attribute)
- {
- $formName = $model->formName();
- if (!preg_match('/(^|.*\])(\w+)(\[.*|$)/', $attribute, $matches)) {
- throw new InvalidParamException('Attribute name must contain word characters only.');
- }
- $prefix = $matches[1];
- $attribute = $matches[2];
- $suffix = $matches[3];
- if ($formName === '' && $prefix === '') {
- return $attribute . $suffix;
- } elseif ($formName !== '') {
- return $formName . $prefix . "[$attribute]" . $suffix;
- } else {
- throw new InvalidParamException(get_class($model) . '::formName() cannot be empty for tabular inputs.');
- }
- }
-
- public static function getInputId($model, $attribute)
- {
- $name = static::getInputName($model, $attribute);
- return str_replace(array('[]', '][', '[', ']', ' '), array('', '-', '-', '', '-'), $name);
- }
}