5

I created a CGridView in Yii whose rows are read from an XML file. I'm not using any models: only a controller (where I read the file) and a view (where I display the grid). What I cannot create is a filter (one input field per column) in the first row of the grid so to visualize only certain rows. How can I do it?

This is what I have until now:

Controller:

<?php
class TestingController extends Controller {
    public function actionIndex() {
        $pathToTmpFiles = 'public/tmp';
        $xmlResultsFile = simplexml_load_file($pathToTmpFiles.'/test.xml');
        $resultData = array();
            foreach ($xmlResultsFile->result as $entry) {
                $chromosome = $entry->chromosome;
                $start = $entry->start;
                $end = $entry->end;
                $strand = $entry->strand;
                $crosslinkScore = $entry->crosslinkScore;
                $rank = $entry->rank;
                $classification = $entry->classification;
                $mutation = $entry->mutation;
                $copies = $entry->copies;
                array_push($resultData, array('Chromosome'=>$chromosome, \
                    'Start'=>$start,  'End'=>$end, Strand'=>$strand, \
                    'Crosslink_Score'=>$crosslinkScore,'Rank'=>$rank, \
                    'Classification'=>$classification, 'Mutation'=>$mutation, \
                    'Copies'=>$copies));
        }
        $this->render('index', array('resultData' => $resultData));
    }
}
?>

View:

<?php
$dataProvider = new CArrayDataProvider($resultData, \
    array('pagination'=>array('pageSize'=>10,),));

$this->widget('zii.widgets.grid.CGridView', array( 'id' => 'mutationResultsGrid',
    'dataProvider' => $dataProvider, 'columns' => array(
        array(
           'name' => 'Chromosome',
           'type' => 'raw',
       ),
       array(
           'name' => 'Start',
           'type' => 'raw',
       ),
       array(
           'name' => 'End',
           'type' => 'raw',
       ),
       array(
           'name' => 'Strand',
           'type' => 'raw',
       ),
       array(
           'name' => 'Crosslink_Score',
           'type' => 'raw',
       ),
       array(
           'name' => 'Rank',
           'type' => 'raw',
       ),
       array(
           'name' => 'Classification',
           'type' => 'raw',
       ),
       array(
           'name' => 'Mutation',
           'type' => 'raw',
       ),
       array(
           'name' => 'Copies',
           'type' => 'raw',
       ),
    ),
));
?>

Thanks for your help Ale

ale ciccia
  • 93
  • 1
  • 5

4 Answers4

7

file: FiltersForm.php (I put it in components folder)

/**
 * Filterform to use filters in combination with CArrayDataProvider and CGridView
 */
class FiltersForm extends CFormModel
{
    public $filters = array();

    /**
     * Override magic getter for filters
     */
    public function __get($name)
    {
        if(!array_key_exists($name, $this->filters))
            $this->filters[$name] = null;
        return $this->filters[$name];
    }

    /**
     * Filter input array by key value pairs
     * @param array $data rawData
     * @return array filtered data array
     */
    public function filter(array $data)
    {
        foreach($data AS $rowIndex => $row) {
            foreach($this->filters AS $key => $value) {
                // unset if filter is set, but doesn't match
                if(array_key_exists($key, $row) AND !empty($value)) {
                    if(stripos($row[$key], $value) === false)
                        unset($data[$rowIndex]);
                }
            }
        }
        return $data;
    }
}

In your controller:

...
$filtersForm = new FiltersForm;
if (isset($_GET['FiltersForm'])) {
    $filtersForm->filters = $_GET['FiltersForm'];
}
$resultData = $filtersForm->filter($resultData);

$this->render('index', array(
    'resultData' => $resultData,
    'filtersForm' => $filtersForm
)}//end action

And last what need - add filters to CGridView config array:

...
'dataProvider' => $dataProvider,
'enableSorting' => true,
'filter' => $filtersForm,
...
Mykytak
  • 183
  • 2
  • 11
1

Why don't you store the information from the xml to a database and use YII ActiveRecord?

In your case you would need a live mechanism to filter the resultset on every filter query. Like with the search() method, when you use YII ActiveRecord models.

So you could use something like array_filter() with callback on your array on every filter call. (Edit: or the mechanism used here with stripos to return the matching "rows": Yii Wiki)

Or, second option, you could make the xml parser dependend on your filter inputs, which does not feel good to me :). The parser would habe to parse on every filter input, which could be a problem with big xml files.

Or, as mentioned, save the information to the database and use standard YII mechanisms.

Sisko78
  • 111
  • 7
0

Assuming you can use the data obtained in the objects in your foreach loop as the filter for that particular column, you could then pass these values through to the view, something like:

<?php
class TestingController extends Controller {
    public function actionIndex() {
        $pathToTmpFiles = 'public/tmp';
        $xmlResultsFile = simplexml_load_file($pathToTmpFiles.'/test.xml');
        $resultData = array();
        foreach ($xmlResultsFile->result as $entry) {
            ...
            $chromosomeFilter[] = $entry->chromosome;
            ...
        }
        $this->render('index', array(
            'resultData'       => $resultData,
            'chromosomeFilter' => $chromosomeFilter,
            ...
        );
    }
}
?>

And then use that value in the filter for that column;

...
array(
    'name'   => 'Chromosome',
    'type'   => 'raw',
    'filter' => $chromosomeFilter,
),
...

I've not tested, and it depends a lot on the structure of your xml and $entry->chromosome, but that might help put you on the right path?

Stu
  • 4,160
  • 24
  • 43
  • Mh.. What I'm trying to achieve is something like this: http://imagebin.org/239196 I'd need a row of text fields (filters) on the first row of the grid, so that only the rows whose entries match to the text you type in the filter will show. Your solution doesn't seem to work, nor I'm able to see how I could proceed from there. – ale ciccia Dec 13 '12 at 16:44
  • have you tried adding a [filter](http://www.yiiframework.com/doc/api/1.1/CGridView#filter-detail) option to your CGridView instance? (rather than to the column, as I did in my example) – Stu Dec 13 '12 at 16:50
  • but with what? If I use this: `$this->widget('zii.widgets.grid.CGridView', array( ... 'filter' => $chromosomeFilter, 'dataProvider' => $dataProvider, ...` I get an "Call to a member function getValidators() on a non-object in ... yii/yii-1.1.6.r2877/framework/web/helpers/CHtml.php on line 1735" – ale ciccia Dec 13 '12 at 16:57
  • I would recommend to go for simple design. Don't use CGridView in this case you'll face issue in between which are critical to handle and eventually we have to move for another option. For more you can read http://www.yiiframework.com/forum/index.php/topic/9365-xml-as-data-source/ – Anup Yadav Dec 13 '12 at 17:06
0

I had the same problem and what I did was I implement http://www.datatables.net/ And pull the data remotely . I pass the sorting and pagination to javascript .

Kevin Florenz Daus
  • 597
  • 3
  • 9
  • 23