You are viewing revision #9 of this wiki article.
This version may not be up to date with the latest version.
You may want to view the differences to the latest version or see the changes made in this revision.
- What is an Action Provider Widget?
- Step 1: Create the Action Class
- Step 2: Configure the Widget
- Step 3: Configure the Controller
- Access Rules
What is an Action Provider Widget? ¶
As written on the API docs: An Action Provider Widget is a widget that has declared several actions by using its 'public static function actions()'. After, a Controller can easily import all its declared actions on its 'public function actions()'.
Step 1: Create the Action Class ¶
For the sake of the article we need to create an action named getData that is supposed to be shared among the whole project and saved with the name getData.php on our protected/components/actions folder.
class getData extends CAction{
public function run(){
echo 'HELLO WORLD';
}
}
Step 2: Configure the Widget ¶
To transform a Widget into an action provider is quite easy (once you know of course). The only thing we need to do is to set the static function actions(). As you will see on the following code, we name the action as GetData and that is the action that will be called in our route. We are going to save the following widget in our protected/components/ folder with the name testProvider.php.
class testProvider extends CWidget{
public static function actions(){
return array(
// naming the action and pointing to the location
// where the external action class is
'GetData'=>'application.components.actions.getData',
);
}
}
Step 3: Configure the Controller ¶
Finally we set our controller’s actions() function to point to our actions provider.
// This function is in this example
// on SiteController
public function actions()
{
return array(
// test. is the prefix we are going to use on our URL
// for all actions within the actionProvider class
// we point to the location where the provider
// is.
'test.'=>'application.components.testProvider',
);
}
All done, now we can call all the actionProvider actions as controllerID/actionPrefix.actionID. Here is the example:
index.php?r=site/test.GetData
Passing Parameters to Actions ¶
As you all know, and already explained in the wiki Actions Code Reuse with CAction, Actions are classes that extend from CAction, that is, a CComponent. If we wish to pass parameters to the actions that are within the provider, we have to do it this way when configuring your controller (step 3) (Thanks to Attilio for pointing this out):
// This function is in this example
// on SiteController
public function actions()
{
return array(
// test. is the prefix we are going to use on our URL
// for all actions within the actionProvider class
// we point to the location where the provider
// is.
'test.'=>array(
'class'=>'application.components.testProvider',
'getData'=>array(
// property1 must be a public variable
// on getData CAction class
'property1'=>'value1',
),
),
);
}
Access Rules ¶
Also, if you have implemented the accessRules method in the controller, make sure that you allow that action in the accessRules method, otherwise you will receive 404 error. So, something like this will do the trick:
public function accessRules()
{
return array(
array('allow',
'actions' => array('test.getData'),
'users' => array('*'),
),
array('deny',
'users' => array('*'),
),
);
}
widget as Action
why do you directly config the actions function of controller like:
return array(
'getData'=>'xx.xxx.getData', );
now we can access it from route: index.php?site/getData;
above is the normally usage;
if follow your way, what's the role of widget? the question is CWidget doesn't extends the CAction , if so we can do a lot , refers to this wiki :http://www.yiiframework.com/forum/index.php?/topic/16357-how-to-use-widget-as-action-provider/page__p__81206__hl__actionPrefix#entry81206
widget as Action
let's say :
class MyActionWidget extends CWidget {
// public $actionPrefix = 'act_'; /*no use*/ public static function actions(){ return array( 'route1'=>'someName', 'route2'=>'someName2', ); } public function someName(){ $this->render('someView1');} public function someName2(){ $this->render('someView2');}
}
in controller
public function actions()
{ return array( 'test.'=>'application.components.MyActionWidget', ); }
know i can access it from route: index.php/site/test.rout1 or index.php/site/test.rout2
the key point is that key in actions function of controller('test.') end with dot '.' will be treated as a widget but a CAction subcalss .
above code just my imagination , please don't mislead by me.
@yiqing95
That is not bad approach. Nevertheless, the point of the article was how Yii uses a widget as an action provider which is not documented elsewhere.
The widget encapsulates all the 'shared' actions throughout our application, that means, that we do not need to 'include' one by one all the shared actions . As you can see on the article, I just need to include the Actions Provider and thats it, all its actions will be included at once. This is the actual role of the widget.
Passing additional parameters to specific actions
@Tony:
Maybe you can inlcude what Attilio found out here?
Incorrect URL
In the default configuration of Yii, the url has to be
index.php?r=site/...
instead of
index.php?site/...
@charliehyii
Thanks charlie... is now fixed
HMVC
Is this how we can implement the HMVC in Yii?
It sounds like what it is discused here HMVC
Action maps are case sensitive
It is worth noting that, opposite to normal actions, actions defined through provider are case sensitive.
For example you can have
public function actionGetData() { ... }
in your controller, and have a link
However, if you define the action through action provider, like in this article, you cannot use
This will give you 404 error. You have to use
about render
Very good wiki!
1) but how create action directly in widget ?
2) how render a view without set entire path ? for example I create a widget for a module
and the only way that works is
$this->controller->render('application.modules.mymodule.views.upload'); because the
$this->render does not works (CAction has not a render method) and the Controller is not the widget itself (because works as provider)
How can I get the current widget to do that ?
Thanks
Re: about render
you can only create Action classes and refer to them in actions() method in the widget. Inline actions are only supported by controllers.
I'm afraid there is no better way to do it currently. You have to use controller render().
Different approach
During my time with Yii I came to prefer not using the suggested design scheme at all. Rather, whenever I have a widget that is required to 'do something', meaning process something on server side as a response to user action on client side, I prefer packing the widget in a module and adding there controller classes, even AJAX only controller action methods.
I find this scheme cleaner and thus easier to maintain. Under this view, a widget is not a swiss army knife but rather used to show stuff to users, and that's it.
Re: about render
Thanks CeBe for your response
1) I supposed, since it is posible use static actions there was a way to do that directly, but as I understand there is no way because in this case widget works as action provider!
2) The anwser is related with first question. If the action could be into widget we could be used $this->render('directlyviewfilename');
re: Different approach
I agree with you Boaz
Actually my widget is an extension of a module!
So the schema is
I want the widget reusable for other uses, thats why this schema!
I could use it as a module inside to another module but is to complicated!
Pass a parameter runtime
Hi
How to pass parameter on runtime ?
For example
'getData'=>array( 'property1'=>(Yii::app()->user->isGuest ? $_GET['property1'] : 'default'), ), Is it corrected ? , I think it isn't...
How to use widget in Model?
I got an Error 500 : Rfpayment and its behaviors do not have a method or closure named "widget".
Method getList() within Rfpayment Model:
public function getList(){ $listData = Feestr::model()->findAll(); $data = array(); foreach ($listData as $l) { $data[$l->id] = $l->title; } $this->widget('ext.select2.ESelect2', array( 'model' => 'Rfpayment', 'attribute' => 'feestructure_id', 'data' => CHtml::listData(Feestr::model()->findAll(), 'id', 'title'), 'options' => array( 'placeholder' => 'Select Payment Name', 'allowClear' => true, ), 'htmlOptions' => array("style" => "width:200px", "autofocus"=>"autofocus", "required"=>"required") )); }
How to resolve such problem?
If you have any questions, please ask in the forum instead.
Signup or Login in order to comment.