0

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?

Teej
  • 12,764
  • 9
  • 72
  • 93

2 Answers2

1

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);
Teej
  • 12,764
  • 9
  • 72
  • 93
tigrang
  • 6,767
  • 1
  • 20
  • 22
  • I need to clarify things. In your answer, you mean to say that one option is to use #1 custom query pagination and #2 is to create a custom find? – Teej Nov 08 '12 at 17:51
  • No, they would be used together. You would create a custom find, and then configure paginator component to use that custom find for the query. First link describes how to configure paginator component, second link on how to create a custom find method. – tigrang Nov 08 '12 at 17:53
  • About the custom query pagination. Wouldn't this override all methods on my Model? just a question. – Teej Nov 08 '12 at 18:43
  • It would change how you call them. Intead of `$this->_getThisMonthsReferers()` you would do something like `$this->find('thisMonthsReferers')` and your `public $paginate = array('findType' => 'thisMonthsReferers')`. You would then need to implement a `_findThisMonthsReferers()` method as outlined in the 2nd link above which would just be altering your current method slightly. – tigrang Nov 08 '12 at 19:17
  • Your answer's probably better but I've solved my problem following Dave's answer. Thanks. I'm still getting my head wrapped over this. – Teej Nov 08 '12 at 20:53
  • Wow. after sleeping it out. I finally got how this custom finders and pagination work together. – Teej Nov 09 '12 at 03:57
  • Yea, `findType` was added in 2.3 (it's still beta though) – tigrang Nov 09 '12 at 04:36
1

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.

Community
  • 1
  • 1
Dave
  • 28,833
  • 23
  • 113
  • 183
  • Yeah, I have thought of this option and was the solution I was about to implement. I just thought that there may be better options. – Teej Nov 08 '12 at 18:40
  • @ThorpeObazee - as you can see in that other question, I usually set it up so I can pass "'paginate'=>true IF I want the options returned instead of the results -that way you can use the function either way. – Dave Nov 08 '12 at 18:50