Widget as an action provider in Yii 2

I’m migrating a complex widget that provides different actions for controllers. The widget is in Yii 1.1 and I’m migrating to Yii 2.0.

For Yii 1.1 the steps described in the topic: action providing widget are sufficient to map actions to the widget and then invoke them in the controller. However, I don’t know if there is the possibility of doing the same in Yii 2.

Each action is a separated class and is called in the widget as follows:

public static function actions() {
        $actions = array(
            'salvar' => 'application.questionarioWidget.actions.SalvarQuestionario',
            'finalizar' => 'application.questionarioWidget.actions.FinalizarQuestionario',
        );
        return $actions;
    }

In the controller I have to define the actions:

public function actions() {
        return array(
            'questionarioWidget.' => 'application.questionarioWidget.questionarioWidget' 
        );
}

In the view, I have a save button that calls the action based on a url dynamically created:

$this->getController()->createUrl('questionarioWidget.salvar')

Everything work well in Yii 1.1, but I’d like to know if is there a way to do the same thing in Yii 2.

Honestly, the widget is huge and complex that could be better to have an alternative approach such as importing Yii 1 widget inside of Yii 2 application. However, it seems to be difficulty as well.

I found a possible solution for the problem as follows:

In my widget I defined the static function actions:

public static function actions()
    {
        return [
            'salvar' => [
                'class' => SalvarQuestionario::class,
            ],            
        ];
}

In the controller I defined the widget actions as follows:

public function actions() {
        return QuestionarioWidget::actions();
}

Finally, in the widget I defined an jquery script that creates the URI for the action to be used in the views where the widget is rendered:

$route = explode('/', Yii::$app->controller->route);
array_pop($route);
$route = implode('/', $route);

        $scriptSubmitButtonSave = '$("#'.$this->saveBtnID.'").on("click", ()=>{
            return submitCall({
                formularioID: "'.$this->CodQuestionario.'",
                btnSalvarID: "'.$this->saveBtnID.'",
                salvarQuestionarioURI: "'.Yii::$app->urlManager->createUrl([
                    $route. '/salvar'
                ]).'"
            });
        })';

In my case, I need to define the variable $route because I have modules and submodules.
The action is being called, however different problems arose because the migration is not finished yet.

I cannot understand what exactly you want to accomplish. I suggest you start migrating it by creating a basic widget that will have basic functionalities first and then move more or even break into multiple widgets: whatever will be practical!

Right,

I will try to be more precise in the explanation.
The widget renders dynamic forms created in an internal system. Commonly, forms are rendered by other applications through the widget.
The questions come from the database, as well as each person’s answers are sent there.

It is likely that there are other solutions that do something similar, however, due to the peculiarities of the questionnaire system, we decided to develop our own.

I don’t see how to break it into multiple widgets, but really, looking at the code I put in it seems quite confusing.

The inserted code snippet is just how the action is performed to save the questionnaire data dynamically.

On the other hand, I managed to solve the problem of providing the action through the widget with the second code above in Yii 2, not so different from how it is in Yii 1.1, where we already have the widget working.

Widgets are for displaying and collecting data. Should not be used to process data. Seems like you need to decouple them.

Are you aware of this extension that can help with dynamic forms

1 Like

That’s one way of looking at it, but I don’t see it that way.
As the documentation says, widgets are reusable blocks used in views to create configurable and complex elements in an object-oriented fashion. Likewise, they must follow the MVC (model-view-controller) pattern. The complexity will depend on each use case.

It is also possible that I have extrapolated the use of the widget, creating an entire system within it. But in this case, it met expectations very well, simply configuring the questionnaire and rendering the widget in a view without having to develop the entire business rule or specific forms, as this is already done dynamically by the widget. The widget I developed makes creating forms much easier. On the other hand, its development was not easy at all, and the size (in complexity) probably exceeds any other widget ever made in our systems since it has its own MVC layer with lots of models to fetch the different types of questions. It’s like a system within a system. =)

As for the widget you mentioned, it does not suit our case, as we have a very complex questionnaire system already used in Yii 1 as a widget. I am working hard to migrate the widget to Yii 2, one step at a time.

I wonder to share with you the codebase to get another point of view or also improvements, but it is a closed system and directed linked to our database.

Thank you for the tips and suggestions.

1 Like