Browse Source

refactoring activeform.

tags/2.0.0-beta
Qiang Xue 12 years ago
parent
commit
784bdb326e
  1. 491
      framework/helpers/base/Html.php
  2. 321
      framework/widgets/ActiveField.php
  3. 235
      framework/widgets/ActiveForm.php

491
framework/helpers/base/Html.php

@ -10,6 +10,7 @@ namespace yii\helpers\base;
use Yii; use Yii;
use yii\base\InvalidParamException; use yii\base\InvalidParamException;
use yii\web\Request; use yii\web\Request;
use yii\base\Model;
/** /**
* Html provides a set of static methods for generating commonly used HTML tags. * Html provides a set of static methods for generating commonly used HTML tags.
@ -397,7 +398,7 @@ class Html
/** /**
* Generates a label tag. * Generates a label tag.
* @param string $content label text. It will NOT be HTML-encoded. Therefore you can pass in HTML code * @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. * it to prevent XSS attacks.
* @param string $for the ID of the HTML element that this label is associated with. * @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. * If this is null, the "for" attribute will not be generated.
@ -609,7 +610,7 @@ class Html
* @param string $name the name attribute. * @param string $name the name attribute.
* @param boolean $checked whether the radio button should be checked. * @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 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 * - 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, * 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 string $name the name attribute.
* @param boolean $checked whether the checkbox should be checked. * @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 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 * - 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, * 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 * 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. * 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; * - 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, * - 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 * 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. * 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; * - 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, * - 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. * @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. * 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. * 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. * - 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. * 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. * @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. * 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. * 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. * - 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. * 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()]]. * 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 * @param string|array $selection the selected value(s). This can be either a string for single selection
* or an array for multiple selections. * or an array for multiple selections.
@ -995,4 +1363,113 @@ class Html
return Yii::getAlias($url); 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);
}
} }

321
framework/widgets/ActiveField.php

@ -0,0 +1,321 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\widgets;
use yii\base\Component;
use yii\helpers\Html;
/**
* @author Qiang Xue <qiang.xue@gmail.com>
* @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);
}
}

235
framework/widgets/ActiveForm.php

@ -8,6 +8,7 @@
namespace yii\widgets; namespace yii\widgets;
use Yii; use Yii;
use yii\base\InvalidCallException;
use yii\base\InvalidParamException; use yii\base\InvalidParamException;
use yii\base\Widget; use yii\base\Widget;
use yii\base\Model; use yii\base\Model;
@ -31,25 +32,26 @@ class ActiveForm extends Widget
* Defaults to 'post'. * Defaults to 'post'.
*/ */
public $method = '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. * @var string the default CSS class for the error summary container.
* @see errorSummary() * @see errorSummary()
*/ */
public $errorSummaryClass = 'yii-error-summary'; public $errorSummaryCssClass = 'yii-error-summary';
public $errorMessageClass = 'yii-error-message';
/** /**
* @var string the default CSS class that indicates an input has error. * @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. * @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. * @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. * @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 * 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 $enableClientValidation = false;
public $options = array(); public $fieldClass = 'yii\widgets\ActiveField';
/** /**
* Initializes the widget. * Initializes the widget.
* This renders the form open tag. * This renders the form open tag.
@ -108,9 +108,9 @@ class ActiveForm extends Widget
unset($options['showAll'], $options['header'], $options['footer'], $options['container']); unset($options['showAll'], $options['header'], $options['footer'], $options['container']);
if (!isset($options['class'])) { if (!isset($options['class'])) {
$options['class'] = $this->errorSummaryClass; $options['class'] = $this->errorSummaryCssClass;
} else { } else {
$options['class'] .= ' ' . $this->errorSummaryClass; $options['class'] .= ' ' . $this->errorSummaryCssClass;
} }
if ($lines !== array()) { if ($lines !== array()) {
@ -124,209 +124,30 @@ class ActiveForm extends Widget
} }
/** /**
* @param Model $model * @var ActiveField[]
* @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
*/ */
public function label($model, $attribute, $options = array()) private $_fieldStack = 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);
}
/** public function beginField($model, $attribute, $options = array())
* @param string $type
* @param Model $model
* @param string $attribute
* @param array $options
*
* @return string
*/
public function input($type, $model, $attribute, $options = array())
{ {
$value = $this->getAttributeValue($model, $attribute); $field = Yii::createObject(array(
$name = $this->getInputName($model, $attribute); 'class' => $this->fieldClass,
if (!array_key_exists('id', $options)) { 'model' => $model,
$options['id'] = $this->getInputId($model, $attribute); 'attribute' => $attribute,
} 'form' => $this,
return Html::input($type, $name, $value, $options); 'options' => $options,
} ));
echo $field->begin();
public function textInput($model, $attribute, $options = array()) return $this->_fieldStack[] = $field;
{
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);
} }
public function checkbox($model, $attribute, $value = '1', $options = array()) public function endField()
{ {
$checked = $this->getAttributeValue($model, $attribute); if ($this->_fieldStack !== array()) {
$name = $this->getInputName($model, $attribute); $field = array_pop($this->_fieldStack);
if (!array_key_exists('uncheck', $options)) { echo $field->end();
$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;
} else { } else {
$value = $model->$attribute; throw new InvalidCallException('The "beginField" and "endField" calls are not matching.');
foreach (explode('][', trim($index, '[]')) as $id) {
if ((is_array($value) || $value instanceof \ArrayAccess) && isset($value[$id])) {
$value = $value[$id];
} else {
return null;
}
}
return $value;
} }
} }
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);
}
} }

Loading…
Cancel
Save