3

I've created a custom handler for a counter virtual field for my module but it seems that I am doing something wrong since I can't sort it nor filter on it as a numeric field. Any one can tell what I need to add to the query method in order to actually place the values in the tables for views to use it?

class mymodule_handler_field_count_for_interval extends views_handler_field_numeric {

    function query() {
        $this->ensure_my_table();
        $this->add_additional_fields();
    }

    function pre_render(&$values){
        foreach ($values as $key=>$value){
            $values[$key]->count=$this->my_module_count($value->nid); 
        }   
    }

    function render($values) {
        $count = $values->count;
        return $count;
    }

    function mymodule_count($nid){
        $count=0;
        if (isset($this->view->filter['timestamp'])) {
            $filter_operator=strtoupper($this->view->filter['timestamp']->operator);
            $filter=$this->view->filter['timestamp'];
            $query=db_select('my_module_table','s');

                switch ($filter_operator){
                    case '<':
                    case '<=':
                    case '>':
                    case '>=':
                        //building the query
                        $query->condition('timestamp',strtotime($filter->value['value']),$filter_operator)
                        ->condition('nid',$nid,'=')
                        ->fields('s',array('sid'))
                        ->addExpression('COUNT(sid)','sid_count');
                        $result=$query->execute();
                        foreach ($result as $count_row){
                            //counting 
                            $count+=$count_row->sid_count;
                        }
                        break;
                    case 'between':
                    case 'not between':
                        //building the query

                        $query->condition('timestamp',array(strtotime($filter->value['min']),strtotime($filter->value['max'])),$filter_operator)
                        ->condition('nid',$nid,'=')
                        ->fields('s',array('sid'))
                        ->addExpression('COUNT(sid)','sid_count');
                        $result=$query->execute();
                        foreach ($result as $count_row){
                            //counting 
                            $count+=$count_row->sid_count;
                        }
                        break;
                }
        }
        return $count;
    }
}

To clarify a bit the question here is my custom module table in the install file(hook_schema).

function my_module_schema(){
$schema['my_module_table']=array(
        'description'=>t('the base table for our statistics'),
        'fields'=>array(
            'sid'=>array(
                'description'=>t('The index field'),
                'type'=>'serial',
                'unsigned'=>TRUE,
                'not null'=>TRUE,
            ),
            'uid'=>array(
                'description'=>t('The user UID'),
                'type'=>'int',
                'unsigned'=>TRUE,
                'not null'=>TRUE,
            ),
            'nid'=>array(
                'description'=>t('The node NID'),
                'type'=>'int',
                'unsigned'=>TRUE,
                'not null'=>TRUE
            ),
            'tid'=>array(
                'description'=>t('The node TID for the category taxonomy.'),
                'type'=>'int',
                'unsigned'=>TRUE,
                'not null'=>FALSE
            ),
            'access_type'=>array(
                'description'=>t('The access type: 0=>web, 1 =>mobile, 2=>barcodescan'),
                'type'=>'int',
                'size'=>'tiny',
                'unsigned'=>TRUE,
                'not null'=>TRUE,
            ),
            'timestamp'=>array(
                'description'=>t('The time of viewing'),
                'type'=>'int',
                'unsigned'=>TRUE,
                'not null'=>TRUE
            ),
        ),
        'unique keys' => array(
            'sid' => array('sid'),
        ),
    );
    return $schema;
}

As you can see it would be very difficult to keep another table with counters because the data is modified per second/minute and users accessing the nodes are different. so what I'd like to understand is how to make views see that I am building a numeric virtual field and where to put it in the views tables so it does the query from its internal tables. Is that possible?

0

Fields, filtering and sorting are implemented by separate handlers. In your case, since your data is virtual, you will need to write your own handlers. You should probably look at extending views_handler_filter_numeric and views_handler_sort. Then in your mymodule.views.inc file you would have something like:

$data['mytable']['count_for_interval'] = array(
 'title' => t('Count for interval'),
 'help' => t('Number of counts in interval.'),
 'field' => array(
   'handler' => 'mymodule_handler_field_count_for_interval',
   'click sortable' => TRUE,
 ),
 'filter' => array(
   'handler' => 'mymodule_handler_filter_count_for_interval',
 ),
 'sort' => array(
   'handler' => 'mymodule_handler_sort_count_for_interval',
 ),
 'argument' => array(
   'handler' => 'views_handler_argument_numeric',
 ),

);

  • I agree with you, but since I know for sure that I am creating a numeric field I would like to avoid creating my own filter, sort, argument handler for it. Is that possbile? – cmos Nov 4 '11 at 8:59
  • Possible? Perhaps, but above you are already rewriting code that is in the existing handlers I mentioned. You will write less and be able to take advantage of built-in features by extending what's built into Views already. – keithm Nov 4 '11 at 10:30
0

If you want to be able to sort by values which aren't in the database you definitive need to write the data into the database.

Once you have this you can write a views integration for this field in the database and you are fine.

  • since is a matter of avoiding a few more queries for each access replacing it with 1 query at presentation (views) I would prefer to use some kind of virtual table inside the view object. is that possible? – cmos Nov 4 '11 at 8:55
  • No it's not, you can only use tables in sql, because that's what views uses for filtering. – Daniel Wehner Nov 4 '11 at 14:03
  • just to be sure. I hope you understand that I cannot vote for both answers even if both are correct. I will go for the first option here. – cmos Nov 10 '11 at 8:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.