简体   繁体   中英

How did $data extracted from dataprovider when using clistview widget?

In yii framework demos, there is an blog demo. In this blog demo a Post controller has two different actions: index and view.

/**
 * Lists all models.
 */
public function actionIndex()
{
    $criteria=new CDbCriteria(array(
        'condition'=>'status='.Post::STATUS_PUBLISHED,
        'order'=>'update_time DESC',
        'with'=>'commentCount',
    ));
    if(isset($_GET['tag']))
        $criteria->addSearchCondition('tags',$_GET['tag']);

    $dataProvider=new CActiveDataProvider('Post', array(
        'pagination'=>array(
            'pageSize'=>Yii::app()->params['postsPerPage'],
        ),
        'criteria'=>$criteria,
    ));

    $this->render('index',array(
        'dataProvider'=>$dataProvider,
    ));
}


/**
 * Displays a particular model.
 */
public function actionView()
{
    $post=$this->loadModel();
    $comment=$this->newComment($post);

    $this->render('view',array(
        'model'=>$post,
        'comment'=>$comment,
    ));
}

and index view is:

<?php $this->widget('zii.widgets.CListView', array(
    'dataProvider'=>$dataProvider,
    'itemView'=>'_view',
    'template'=>"{items}\n{pager}",
)); ?>

and view view is:

<?php $this->renderPartial('_view', array(
    'data'=>$model,
)); ?>

but both index and view use _view:

<div class="author">
    posted by <?php echo $data->author->username . ' on ' . date('F j, Y',$data->create_time); ?>
</div>
<div class="content">
    <?php
        $this->beginWidget('CMarkdown', array('purifyOutput'=>true));
        echo $data->content;
        $this->endWidget();
    ?>
</div>

here is my question: I can understand the view assign the 'data' => $model, so in _view, $data is valid. In index action, the widget clistview is applied, but i cannot understand where is $data variable being set? I know the $data presents the current post(from dataprovider). I just cannot figure out how and where did yii did this? Thanks for any help.

The above code first creates a data provider for the Post ActiveRecord class. It then uses CListView to display every data item as returned by the data provider. The display is done via the partial view named '_post'. This partial view will be rendered once for every data item. In the view, one can access the current data item via variable $data.

By using the itemView property of CListView which is used for rendering each data item. This property value will be passed as the first parameter to CController property renderpartial to render each data item.

public string renderPartial(string $view, array $data=NULL, boolean $return=false, boolean $processOutput=false)

public function renderPartial($view,$data=null,$return=false,$processOutput=false)
{
    if(($viewFile=$this->getViewFile($view))!==false)
    {
        $output=$this->renderFile($viewFile,$data,true);
        if($processOutput)
            $output=$this->processOutput($output);
        if($return)
            return $output;
        else
            echo $output;
    }
    else
        throw new CException(Yii::t('yii','{controller} cannot find the requested view "{view}".',
            array('{controller}'=>get_class($this), '{view}'=>$view)));
}

Renders a view.

If $data is an associative array, it will be extracted as PHP variables and made available to the script The named view refers to a PHP script .the Script Which is resolved via getViewFile Used in the renderPartial method the script for getViewFile as shown below

public function getViewFile($viewName)
{
    if(($theme=Yii::app()->getTheme())!==null && ($viewFile=$theme->getViewFile($this,$viewName))!==false)
        return $viewFile;
    $moduleViewPath=$basePath=Yii::app()->getViewPath();
    if(($module=$this->getModule())!==null)
        $moduleViewPath=$module->getViewPath();
    return $this->resolveViewFile($viewName,$this->getViewPath(),$basePath,$moduleViewPath);
}

Looks for the view file according to the given view name.

renderItems is the abstract method defined in CBaseListView ClassFile

/**
     * Renders the data items for the view.
     * Each item is corresponding to a single data model instance.
     * Child classes should override this method to provide the actual item rendering logic.
     */

    abstract public function renderItems(); 

And This Method is Overriden by ClistView Class

CListView widget loops thru $dataProvider , and for each item it does something like that:

$this->renderPartial($itemView, array(
   'data'=>$model,
));

Where $itemView is view file set in CListView config.

And that's it.

Edit : To clarify of how CListView iterates over dataprovider items : it is defined in CListView::renderItems , in short, the most important parts are:

// Get dataprovider data as array
$data=$this->dataProvider->getData();
...
// Get viewfile
$viewFile=$owner->getViewFile($this->itemView);
...
// Loop thru $data items
foreach($data as $i=>$item)
{
    ...
    // Here data is assigned from dataprovider item
    $data['data']=$item;
    ...
    // Render view file
    $owner->renderFile($viewFile,$data);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM