statefulForm
方法 生成一个有状态的表单标签。一个有状态的表单标签类似于form,除这以外,它还可以渲染一个附加的用于持久存储页面状态的隐藏域。如果你想在表单提交的时候可以访问页面持久状态,那么你就可以用这个方法生成一个表单标签
public static function statefulForm($action='',$method='post',$htmlOptions=array())
{
return self::form($action,$method,$htmlOptions)."\n".
self::tag('div',array('style'=>'display:none'),self::pageStateField(''));
}
public static function pageStateField($value)
{
return '<input type="hidden" name="'.CController::STATE_INPUT_NAME.'" value="'.$value.'" />';
}
classCControllerextendsCBaseController |
{ |
/** |
* Name of the hidden field storing persistent page states. |
*/ |
const STATE_INPUT_NAME='YII_PAGE_STATE'; |
Saves a persistent page state value. A page state is a variable that is persistent across POST requests of the same page. In order to use persistent page states, the form(s) must be stateful which are generated using CHtml::statefulForm.
public function setPageState($name,$value,$defaultValue=null)
{
if($this->_pageStates===null)
$this->_pageStates=$this->loadPageStates();
if($value===$defaultValue)
unset($this->_pageStates[$name]);
else
$this->_pageStates[$name]=$value;
$params=func_get_args();
$this->recordCachingAction('','setPageState',$params);
}
Returns a persistent page state value. A page state is a variable that is persistent across POST requests of the same page. In order to use persistent page states, the form(s) must be stateful which are generated using CHtml::statefulForm.
public function getPageState($name,$defaultValue=null)
{
if($this->_pageStates===null)
$this->_pageStates=$this->loadPageStates();
return isset($this->_pageStates[$name])?$this->_pageStates[$name]:$defaultValue;
}
Loads page states from a hidden input.
protected function loadPageStates()
{
if(!empty($_POST[self::STATE_INPUT_NAME]))
{
if(($data=base64_decode($_POST[self::STATE_INPUT_NAME]))!==false)
{
if(extension_loaded('zlib'))
$data=@gzuncompress($data);
if(($data=Yii::app()->getSecurityManager()->validateData($data))!==false)
return unserialize($data);
}
}
return array();
}
These type of forms are similar to how Prado keeps the state of a page throughout subsequent POST requests. The basic idea is, that there's a hidden field, that can contain arbitrary information. You can use setPageState() to save a name/value pair in this page state. With every POST, this state information is submitted with the request and available in the next action through getPageState(). If the page is requested via GET, all state will be lost.
The hangman demo uses this to store information of the current game. One advantage of this method is, that it's independent of sessions and thus a user can even have multiple browser windows open with different games
As I take a look into CController->loadPageStates(), there's no code to load page states from GET method. I think it sounds confused to the users since they can set GET method to the form in CHtml::statefulForm(), but no way to get the states back. I don't know if the dev team has a good reason why they don't put this GET detection into the method.
I know this is NOT the bug. it's mostly the issue, and I hope the framework should be able to do it without any overrides.
For people who needs to get the states using GET method, you can override the loadPageStates() then add your detection code into it.
stateFulForm 就是一个保存用户数据的一个表单,这个表单不同之处是他可以保存一个数据在当前请求和下次请求中。如果是设置stateFulForm为get请求,则这个数据会丢失。
例子:
Actually is a way to store some application data in the result html code and get them back at the next request.
E.g. a page has counter that shows how many times a button on the same page is clicked.
With statefulForm, the action that handles this, could be:
publicfunction actionCounter()
{
$count = $this->getPageState('clicks',0);
$this->setPageState('clicks', $count +1);
$this->render('counter', array('count'=> $count,));
}
Where 'clicks' is an arbitrary name that is used as array key, and 0 is the default value if no 'clicks' PageState have set before.
Counter view could now be:
<h2>You have clicked <?php echo $count?> times</h2>
<?php echo CHtml::statefulForm();?>
<?php echo CHtml::submitButton('Click Me!');?>
</form>
生成的结果为:
<form method="post" action="/personal/personal/test">
<div style="display:none">
<input type="hidden" value="eJwFwcERgCAMBMBeqCDhCGioJoYw40cf6suxd3elgi2IeCzUNs+NEGajlDXDUNkFiAmYsr6XiiY/n+NOfdfSvx8IihFK" name="YII_PAGE_STATE">
</div>
<input type="submit" value="submit" name="yt0">
<div class="clear"></div>
</form>
This would also be possible with sessions (see cookies)