Zii For Non-active Records

I would like to use Zii widgets for generic data models represented as objects or arrays without a database table.

In an attempt to serve an array as a data model, I tried extending CDataProvider by creating an ArrayDataProvider component as follows:




class ArrayDataProvider extends CDataProvider

{

    /**

     * The array containing our data. Format is:

     * array (

     *      array('col1'=> 1, 'col2'=> 2, 'col3'=> 3, ...),   // Row 1

     *      array('col1'=> 1, 'col2'=> 2, 'col3'=> 3, ...),   // Row 2

     *      ...

     * );

     */

    public $dataArray;


    public function __construct($dataArray)

    {

        if(empty($dataArray))

            throw new CException('Empty Array given.');

        $this->dataArray = $dataArray;

        $this->setId(mt_rand(0, 10000));     // Without this CDataProvider expects $this->modelClass.

    }


    protected function fetchData()

    {

        return $this->dataArray;

    }


    protected function fetchKeys()

    {

        return empty($this->dataArray[0]) ? null : array_keys($this->dataArray[0]);

    }


    protected function calculateTotalItemCount()

    {

        return count($this->dataArray);

    }

}



In the controller I create some test data and pass it to the view:




    public function actionSearch()

    {

        //$dataProvider = new CActiveDataProvider('Inventory');

        $data = array(

            array('date' => '2010-01-19', 'itemID'=> '2', 'count'=> '5'),

            array('date' => '2010-01-20', 'itemID'=> '2', 'count'=> '5'),

            array('date' => '2010-01-21', 'itemID'=> '2', 'count'=> '5'),

            array('date' => '2010-01-22', 'itemID'=> '2', 'count'=> '5'),

            array('date' => '2010-01-23', 'itemID'=> '2', 'count'=> '5'),

            array('date' => '2010-01-24', 'itemID'=> '2', 'count'=> '5'),

            array('date' => '2010-01-25', 'itemID'=> '2', 'count'=> '5'),

            array('date' => '2010-01-26', 'itemID'=> '2', 'count'=> '5')

        );

        $dataProvider = new ArrayDataProvider($data);

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

    }



The view uses CGridView:




$this->widget('zii.widgets.grid.CGridView', array(

    'dataProvider'=>$dataProvider

));



When I run this however, no data appears. The HTML output does contain column names but no data:

[html]

<div id="yw0" class="grid-view">

<div class="keys" style="display:none" title="/yii_app/index.php?r=mod/default/search"><span>date</span><span>itemID</span><span>count</span></div>

<div class="summary">Displaying 1-8 of 8 result(s).</div>

<table class="items">

<thead>

<tr>

</tr>

</thead>

<tbody>

<tr class="odd"></tr>

<tr class="even"></tr>

<tr class="odd"></tr>

<tr class="even"></tr>

<tr class="odd"></tr>

<tr class="even"></tr>

<tr class="odd"></tr>

<tr class="even"></tr>

</tbody>

</table>

<div class="pager"></div></div>

[/html]

Am I missing something? Currently, it appears that Zii is coupled to active records by using CActiveDataProvider. Is it possible to use Zii widgets for data whose source is not a relational database, such as a web service, LDAP directory service, or a CSV file?

Thanks,

Sunpreet.

(PS: I have seen the CArrayDataProvider extension but it still requires active records.)

I’m also really interested in this idea. I’m going to see if I can work with the idea posted above and get it to work. However, if there’s a smarter way to do this or it’s already been done, I’d love to hear it!

So, I’ve made a little progress. Managed to get it to display some information. Using the class above as a skeleton, I modified to override the getData() and getKeys() methods, along with the setData() method. The reason is because since we need to use a separate var for storage in this class, I did not want to assume that CDataProvider::set/getData() would use the fetchKeys() and fetchData() methods. Overriding them seems to allow it to work… partially. Another issue that occurs is that when called zii.widgets.grid.CGridView, one must specify the columns to be displayed too. Code provided below:


class ArrayDataProvider extends CDataProvider {

    /**

     * The array containing our data. Format is:

     * array (

     *      array('col1'=> 1, 'col2'=> 2, 'col3'=> 3, ...),   // Row 1

     *      array('col1'=> 1, 'col2'=> 2, 'col3'=> 3, ...),   // Row 2

     *      ...

     * );

     */


    public $data;


    public function __construct( $dataArray ) {

        $this->setData( array( $dataArray ) );

        $this->setKeys( $this->fetchKeys() );

        $this->setId( mt_rand( 0, 10000 ) );     // Without this CDataProvider expects $this->modelClass.

    }


    protected function fetchData() {

        return $this->data;

    }


    protected function fetchKeys() {

        return empty( $this->data ) ? null : array_keys( $this->data );

    }


    protected function calculateTotalItemCount() {

        return count( $this->data );

    }


    public function getData( $refresh = false ) {

        return $this->fetchData();

    }


    public function getKeys( $refresh = false ) {

        return $this->fetchKeys();

    }


    public function setData( $array ) {

        $this->data = $array;

    }

}

To use:


<?php 

    $dp = new ArrayDataProvider( array( "some data" ) );

    $this->widget('zii.widgets.grid.CGridView', array(

	'dataProvider'=> $dp,

    'columns' => array(

        'col1',

        'col2',

    ),

)); ?>

Granted, specifying the columns is kind of annoying. It might just be a matter of overriding some tagging information. I’ll update when I find out.

There is some mistake:

If you use for data array like this:




      array (

           array('col1'=> 1, 'col2'=> 2, 'col3'=> 3, ...),   // Row 1

           array('col1'=> 1, 'col2'=> 2, 'col3'=> 3, ...),   // Row 2

           ...

      );

you need to use


$this->setData( $dataArray );

, instead of


$this->setData( array( $dataArray ) );

Next question for this, how to use sort for this?

I`m using my CPdoDataProvider

This class execute SELECT and put result in CDataProvider. This is allow use SELECT query with CGridView and CListView