I have used CCaptcha in other widget (my own). Widget could be rendered in many places (other controllers and actions), but form attribute action is on SiteController (actionContact).
I have moved CCaptcha action on my base controller (which other controllers extends), and there is a problem…
If I send form from SiteController action - everything is fine, but if I send it from another controller, captcha isn’t valid. CCaptchaAction generates a new key (when controller is changing to SiteController - where form attribute action is lead to), and my input value key is comparing with this new key - so it is not valid everytime
Is there any (simple=better) way to receive this goal?
I’ve had the same problem and solved it by extending CCaptcha class.
Below full code of my new class:
<?php
class ExtendedCCaptcha extends CCaptcha
{
public $controllerId;
/**
* Renders the CAPTCHA image.
*/
protected function renderImage()
{
if(isset($this->imageOptions['id']))
$id=$this->imageOptions['id'];
else
$id=$this->imageOptions['id']=$this->getId();
if (isset($this->controllerId))
{
$url=Yii::app()->createUrl("$this->controllerId/".$this->captchaAction,array('v'=>uniqid()));
}
else
{
$url=$this->getController()->createUrl($this->captchaAction,array('v'=>uniqid()));
}
$alt=isset($this->imageOptions['alt'])?$this->imageOptions['alt']:'';
echo CHtml::image($url,$alt,$this->imageOptions);
}
/**
* Registers the needed client scripts.
* @since 1.0.2
*/
public function registerClientScript()
{
$cs=Yii::app()->clientScript;
$id=$this->imageOptions['id'];
if (isset($this->controllerId))
{
$url=Yii::app()->createUrl("$this->controllerId/".$this->captchaAction,array(CCaptchaAction::REFRESH_GET_VAR=>true));
}
else
{
$url=$this->getController()->createUrl($this->captchaAction,array(CCaptchaAction::REFRESH_GET_VAR=>true));
}
if($this->showRefreshButton)
{
$cs->registerScript('Yii.CCaptcha#'.$id,'dummy');
$label=$this->buttonLabel===null?Yii::t('yii','Get a new code'):$this->buttonLabel;
$button=$this->buttonType==='button'?'ajaxButton':'ajaxLink';
$html=CHtml::$button($label,$url,array('success'=>'js:function(html){jQuery("#'.$id.'").attr("src",html)}'),$this->buttonOptions);
$js="jQuery('img#$id').after(\"".CJavaScript::quote($html).'");';
$cs->registerScript('Yii.CCaptcha#'.$id,$js);
}
if($this->clickableImage)
{
$js="jQuery('#$id').click(function(){"
.CHtml::ajax(array(
'url'=>$url,
'success'=>"js:function(html){jQuery('#$id').attr('src',html)}",
)).'});';
$cs->registerScript('Yii.CCaptcha#2'.$id,$js);
}
}
}
?>
With this it seems to work, it only requires to set property for $controllerId like any other property of CCaptcha, and its not full name of controller but its ID as You can use while making URL with Yii::app()->createUrl(…) function (that means for “SiteController” it’s “site” and for AnyController it would be “any”). If u forget to set ‘controllerId’ - it should work as CCaptcha does.
I’ve made it this way, becouse I wanted my widget (it is rendered inside of SideBar) to call through ajax only 1 function in specified controller (SiteController in my case), and with this I got it to work.
I had problem rendering the image (I have a cuiDialog in which I use renderPartial to get site/contact, found your post and it worked! Though I cant tell if the validation work yet.