I’m almost sure I’ve found a bug.
How to reproduce it:
Create a "Action Provider Widget", following How to use a widget as action provider and passing parameters as said in the last section "Final notes, Actions code reuse with CAction"
This is the final code:
CAction:
class saveJpg extends CAction{
public $filepath;
public function run(){
$filepath = $this->filepath;
print "OK: $filepath";
}
}
Widget (relevant part only):
public static function actions()
{
return array(
'saveJpg'=>'application.extensions.myext.actions.saveJpg',
);
}
Client code Controller (relevant part only):
public function actions()
{
return array(
'myext.'=> array(
'class'=>'application.extensions.myext.Myext',
'filepath'=> 'something'
)
);
}
Calling url //localhost/mysite/mycontroller/myext.saveJpg prints ‘OK’ without ‘something’
1st confirmation of the bug:
I’ve tried some debugging following Mike’s suggestion
I’ve added some ‘echo’ and ‘print_r’ to framework/web/CController.php’s createActionFromMap function without changing the behaviour of the method:
protected function createActionFromMap($actionMap,$actionID,$requestActionID,$config=array())
{
echo "am: "; print_r($actionMap); echo " aid: "; print_r($actionID); echo " raid: "; print_r($requestActionID); echo " conf: "; print_r($config); echo "\n\n";
if(($pos=strpos($actionID,'.'))===false && isset($actionMap[$actionID]))
{
$baseConfig=is_array($actionMap[$actionID]) ? $actionMap[$actionID] : array('class'=>$actionMap[$actionID],/*'filepath'=> 'something'*/);
echo "bc: "; print_r($baseConfig); echo " c: "; print_r($config); echo "\n";
return Yii::createComponent(empty($config)?$baseConfig:array_merge($baseConfig,$config),$this,$requestActionID);
}
else if($pos===false)
return null;
// the action is defined in a provider
$prefix=substr($actionID,0,$pos+1);
if(!isset($actionMap[$prefix]))
return null;
$actionID=(string)substr($actionID,$pos+1);
$provider=$actionMap[$prefix];
if(is_string($provider))
$providerType=$provider;
else if(is_array($provider) && isset($provider['class']))
{
$providerType=$provider['class'];
if(isset($provider[$actionID]))
{
if(is_string($provider[$actionID]))
$config=array_merge(array('class'=>$provider[$actionID]),$config);
else
$config=array_merge($provider[$actionID],$config);
}
}
else
throw new CException(Yii::t('yii','Object configuration must be an array containing a "class" element.'));
$class=Yii::import($providerType,true);
$map=call_user_func(array($class,'actions'));
echo "Poor conf: "; print_r($config); echo "\n";
return $this->createActionFromMap($map,$actionID,$requestActionID,$config);
}
and this is the produced output:
am: Array
(
[jpegcam.] => Array
(
[class] => application.extensions.jpegcam.Jpegcam
[filepath] => mio
)
)
aid: jpegcam.saveJpg raid: jpegcam.saveJpg conf: Array
(
)
Poor conf: Array
(
)
am: Array
(
[saveJpg] => application.extensions.jpegcam.actions.saveJpg
)
aid: saveJpg raid: jpegcam.saveJpg conf: Array
(
)
bc: Array
(
[class] => application.extensions.jpegcam.actions.saveJpg
)
c: Array
(
)
OK:
As you can see the method calls itself (each call starts with ‘am:’ for $actionMap) but it looses the parameters between the first and the second call (check ‘Poor conf’ line)
2nd confirmation of the bug:
If I decomment the final part of
$baseConfig=is_array($actionMap[$actionID]) ? $actionMap[$actionID] : array('class'=>$actionMap[$actionID],/*'filepath'=> 'something'*/);
then I get the expected result: OK: something.