How to use widget as action provider?


(Poppitypop) #1

I would like to access an action defined in my widget via a controller. I would like to access the actionGetData() action in my WeekReport widget via the route r=controller/weekReport.getData

This is what I have in my controller:


	public function actions() {

		return array(

			'weekReport.'=>'application.components.WeekReport'

		);

	}

And in my widget:




	public $actionPrefix = 'action';

	

	public static function actions() {

		return array(

			'getData'=>'WeekReport'

		);

	}

	public function actionGetData() {

		//...

	}



But Yii throws this error:

Any help? I can not find any good examples to reference…


(Pr0j3ct A1ex) #2

	public function actions() {

		return array(

			'weekReport.GetData'=>'application.components.WeekReport'

		);

	}

Do you not need to match the full action name in the actions array?


(Antonio) #3

dont you need to set your actionPrefix in your widget as weekReport ? http://www.yiiframework.com/doc/api/1.1/CWidget#actions-detail


(Mh) #4

Not sure, how it’s supposed to be configured - but i think you should leave actionPrefix empty. Otherwhise you’d have to add it to your actionIDs in your route.

EDIT:

Sorry, Antonio, you actually pointed to the same direction. Didn’t read carefully enough.


(Poppitypop) #5

I am now using the full path in my widget:


        public function actions() {

                return array(

                        'weekReport.GetData'=>'application.components.WeekReport'

                );

        }

Now I just get a blank page. I tried setting the $actionPrefix to ‘’, ‘action’, ‘weekReport’, ‘weekReport.’. Still get blank page… I can tell that the widget is being loaded on the request to controller/weekReport.getData. It just does not execute the action


(Antonio) #6

I know now how it works, here the steps my friend:





// create an action class

<?php


class getData extends CAction{

	public function run(){

		echo 'HELLO WORLD';


	}

}


// in your widget:

<?php

class weekReport extends CWidget{

	

	public $actionPrefix = 'test.';

	

       // now is an action provider 

	public static function actions(){

		return array(

		   'GetData'=>'application.components.actions.getData',

		);

	}

}


// in your controller

public function actions()

	{


		return array(

			'test.'=>'application.components.weekReport',

		);

	}


// to call it

index.php?r=site/test.GetData



I really enjoyed this post… :) I think i will write a wiki about it…


(Poppitypop) #7

I was starting to suspect that that was the only solution…

Is there no way to put the action in the widget itself? After all, CWidget extends CBaseController.

The reason I would like to do this is to easily re-use methods that I have defined in the widget.

I could always use a third component for the common code in the widget… But I think it would be nice if we could define actions in widgets themselves


(Antonio) #8

I tried that before creating external CAction files but no luck. As you said, it could be a nice feature to enhance future releases (you are part of the team) with encapsulated actions instead of just external ones.


(Poppitypop) #9

I created a ticket for this. I am actually not on the dev team anymore… Since I started studying at UC Berkeley as an Electrical Engineering & Computer Sciences major I have not had much time anymore to devote to Yii. IDK why I am still a forum mod…


(Antonio) #10

Hi Jonah,

I found another way to do it by using the run method and checking the actual request. I know it is not what is supposed to be done but… actions are called using the run() method of the component, so you can create a workaround on your widget.




        public static function actions(){

		return array(

			'test'=>'application.components.weekReport',

		);

	}

	public function actionTest(){

		echo 'Test';

	}

	public function run(){

              

		$uri = (Yii::app()->getRequest()->getRequestUri());

		

		$method = 'action'.ucfirst(substr($uri,strrpos($uri,'.')+1));

		$this->$method();

	}


//  use same as before for your controller,

// and to call it

index.php?r=site/test.Test



Good luck with your studies… I wish you the best (I am actually envying you a bit :) )


(Poppitypop) #11

Ah… this is very nice except one set-back. The run() method also happens to be called on CBaseController::endWidget(). So when I try to use the widget as an actual widget, the action will also be called which is not desirable in my case.

A workaround though would be to set a flag in init() (which is called in CBaseController::createWidget()) so in run() we can tell how it was called. There are other workarounds too…