user213154
user213154

Reputation:

Use a widget in a statically-called method

Normally a widget is used by calling CController::widget() on an instance of CController, typically $this in a view.

But if I'm writing a static method, a helper, say, then I don't have access to an instance of CController. So how do I use a widget?

Let's say further that this helper method is invoked in the eval()’ed expression in a CDataColumn's value property. That poor expression has almost no context at all. How should the helper use a widget?


EDIT: Code example

As requested, a view example:

$this->widget('zii.widgets.grid.CGridView', array(
    'dataProvider' => $model->search(),
    'columns' => array(
        array(
            'name' => 'attrName',
            'value' => '--USE WIDGET HERE--',
        ),
    )
));

Upvotes: 2

Views: 3915

Answers (3)

Stas Panyukov
Stas Panyukov

Reputation: 368

This one is working solution for calling widgets in static methods in Yii

Yii::app()->controller->widget('widget');

Upvotes: 3

user213154
user213154

Reputation:

This answer doesn't answer the question in general but in the specific case—how to access the controller and use a widget in the context of the evaluated expression of CDataColumn::$value—you can use this:

$this->widget('zii.widgets.grid.CGridView', array(
    'dataProvider' => $model->search(),
    'columns' => array(
        array(
            'name' => 'attrName',
            'value' => function ($data, $row, $column) {
                $controller = $column->grid->owner;
                $controller->widget(/* ... etc ... */);
            }, 
        ),
   )
));

The trick was discovering that CDataColumn::renderDataCellContent() uses CComponent::evaluateExpression(), which injects the component instance into the callback as the last parameter. In this case that omponent is the CDataColumn, which references the controller as shown.

I don't like writing PHP expressions as string literals so I'm pleased to find this option.

A comment on http://www.yiiframework.com/doc/api/1.1/CDataColumn#value-detail shows another way to us a widget in a column value that I haven't tried.

Upvotes: 6

Alfredo Castaneda Garcia
Alfredo Castaneda Garcia

Reputation: 1659

There's no direct way to call a widget out of controller because you shouldn't do so. It's all about MVC. Widgets are only needed and/or useful in views, and views are only accessed via controllers. That's the theory.

I guess you're approaching the problem mistakenly. A proper, MVC-friendly way to do what your're trying to do involves using renderPartial(). You know: you a have certain content and you want to decorate it (in your case you want to imbibe it inside a widget, right?) before displaying it to final user; so, from the view, you call renderPartial(). It will send your data to a file where it will properly decorated. renderPartial() returns the content properly formatted and now you can display it in the view.

Unfortunately, in your particular case, you're working with grid view (right?) and, at least from my point of view, it makes the things a bit harder. In order to decorate content for a CGridColumn-subclass element (like CDataColumn), you need to override the renderDataCellContent() method. Check it out here: http://www.yiiframework.com/doc/api/1.1/CDataColumn#renderDataCellContent-detail

Upvotes: 1

Related Questions