0
votes

I currently have this in my Model (Referer Model):

public function getReferers($type = 'today') {
    if ($type == 'this_month') {
        return $this->_getThisMonthsReferers();
    } elseif ($type == 'today') {
        return $this->_getTodaysPageReferers();
    }      
}

private function _getThisMonthsReferers() {
    $today = new DateTime();

    return $this->Visitor->find('all', array(
        'fields' => array(
            'Referer.url',
            'COUNT(UserRequest.visitor_id) as request_count',
            'COUNT(DISTINCT(Visitor.id)) as visitor_count',
            'COUNT(UserRequest.visitor_id) / COUNT(DISTINCT(Visitor.id)) as pages_per_visit',
            'COUNT(DISTINCT(Visitor.id)) / COUNT(UserRequest.visitor_id) * 100 as percent_new_visit'
        ),
        'joins' => array(
            array(
                'table' => 'user_requests',
                'alias' => 'UserRequest',
                'type'  => 'RIGHT',
                'conditions' => array(
                    'UserRequest.visitor_id = Visitor.id'
                )
            )
        ),
        'conditions' => array(
            'Visitor.site_id' => $this->Site->id,
            'MONTH(UserRequest.created)' => $today->format('m'),
            'YEAR(UserRequest.created)' => $today->format('Y')
        ),
        'group' => array(
            'url'
        )
    ));
}

The thing is that I how I would paginate this. It will be so easy if just copy my code out of the model and to the controller. The thing is I want the keep the query in my Model.

How is this supposed to be done in CakePHP?

2

2 Answers

1
votes

A custom find type is one method. You can find more information here: http://book.cakephp.org/2.0/en/core-libraries/components/pagination.html#custom-query-pagination

To turn your _getThisMonthsReferers into a custom find, follow this http://book.cakephp.org/2.0/en/models/retrieving-your-data.html#creating-custom-find-types

For example:

// model
protected function _findThisMonthsReferers($state, $query, $results = array()) {
    if ($state === 'before') {
        $query['fields'] = ....
        $query['joins'] = ....
        return $query;
    }
    return $results;
}

// controller
public $paginate = array('findType' => 'thisMonthsReferers')

EDIT:

I think it should be :

public $paginate = array('thisMonthsReferers');

However the Solution I used derived from this answer is adding this to the method I am using

$this->paginate = array('thisMonthsReferers');

Since I don't want i used in all my actions. Then paginating the Model like this.

$this->paginate('Visitor);
1
votes

Instead of returning the results of the find, just return it's array of options:

return array(
    'fields' => array(
    //...etc

Then use those options to paginate in the controller. More details on this answer of this similar question: Paginate from within a model in CakePHP

It still keeps the model fat (with any logic that might alter the conditions, joins, fields...etc), and the controller skinny, which just uses the returned array as paginate options.