在CakePHP 2.x中使用命名参数

I have the following method which takes a query to search my notes:

function search( $q = null )
{
    if ( $q == null )
    {
        $this->redirect(array('action' => 'index'));
    }

    $this->paginate = array(
    'limit'=>5,
    'order'=>'Note.datetime DESC',
    'conditions' => array(
        'OR' => array(
            'Note.title LIKE' => '%'. $q . '%',
            'Note.content LIKE' => '%'. $q . '%'
            )
        ),
        'Note.status'=>1
    );

    $this->set('notes', $this->paginate());

    $this->render('index');
}

As you can see it takes a single parameter called 'q' which is used to query the model data.

I have hooked up this to the router like so:

Router::connect('/notes',
    array('controller'=>'notes','action'=>'index', 'page' => 1),
    array(
        'pass' => array('page')
    )
);

Router::connect('/notes/page/:page', 
    array('controller' => 'notes', 'action' => 'index'),
    array(
        'pass' => array('page'),
        'page' => '[1-9]+'
        )
);

Router::connect('/notes/search/:page/:q',
    array('controller'=>'notes','action'=>'search', 'page' => 1),
    array(
        'pass' => array('page','q')
    )
);

Router::connect('/notes/search/:q/page/:page', 
    array('controller' => 'notes', 'action' => 'search'),
    array(
        'pass' => array('page','q'),
        'page' => '[1-9]+'
        )
);

This way I should be getting urls like:

domain.com/notes - loads page 1 of notes

domain.com/notes/page/2 - loads page 2 of notes

domain.com/notes/search/Hello - searches for Hello in notes

domain.com/notes/search/Hello/page/2 - shows page 2 of the above search

The pager in the view looks like:

<?php if(isset($this->request->params['named']['q'])) { ?>
<?php $this->Paginator->options(array('url'=>array('controller' => 'notes', 'action' => $action, 'q' => $this->request->params['named']['q']))); ?>
<?php } else { ?>
<?php $this->Paginator->options(array('url'=>array('controller' => 'notes', 'action' => $action))); ?>
<?php } ?>

It works fine for the index method, but for the search method it is getting confused as when I do a search it's not matching the pager with the route as expected. For example I'm getting urls like domain.com/notes/search/2/:q

Also I don't really like having to wrap the paginator options in an if statement so if I can get it to figure out the url automatically that would be awesome as it's messy having to do this and seems to be the cause of the above problems.

I have connected the named parameter at the top of the router like so:

Router::connectNamed(array('q'));

In the end I opted to make my search working using POST instead of GET so that everything is handled sever-side instead of doing it with messy url rewrites and trying to be clever.

Here's what I made the form look like:

<?php echo $this->Form->create('search', array('url'=>array('controller'=>'notes','action'=>'search'),'class'=>'search')); ?>
    <label class="placeholder" for="q">Search</label>
    <?php if( isset($q) ) { $term = $q; } else { $term = ''; } ?>
    <?php echo $this->Form->input('q', array('label'=>false,'id'=>'q','value'=>$term)); ?>
    <button type="submit" class="btn ss-icon ss-search"></button>
<?php echo $this->Form->end(); ?>

the search method:

function search()
{
    if ($this->request->is('post')) {

        $this->Session->write('q', $this->request->data['search']['q']);

        $this->redirect(array('action' => 'search'));

    } else {

        $q = $this->Session->read('q');

        $this->paginate = array(
        'limit'=>5,
        'order'=>'Note.datetime DESC',
        'conditions' => array(
            'OR' => array(
                'Note.title LIKE' => '%'. $q . '%',
                'Note.content LIKE' => '%'. $q . '%'
                )
            ),
            'Note.status'=>1
        );

        $this->set('q',$q);

        $this->set('action','search');

        $this->set('notes', $this->paginate());

        $this->render('index');

    }

}

and the routes:

Router::connect('/notes/search',
    array('controller'=>'notes','action'=>'search', 'page' => 1),
    array(
        'pass' => array('page')
    )
);
Router::connect('/notes/search/page/:page', 
    array('controller' => 'notes', 'action' => 'search'),
    array(
        'pass' => array('page'),
        'page' => '[1-9]+'
        )
);

and I clean up the session if any other page but the search method is being used in the AppController:

if(strpos($this->here, Router::url(array('controller'=>'notes','action'=>'search'))) === 0 ) {

    //echo 'yes';

} else {

    $this->Session->delete('q');

}

Which gives me urls like:

domain.com/notes - loads page 1 of notes

domain.com/notes/page/2 - loads page 2 of notes

domain.com/notes/search - searches for Hello in notes (stored in session)

domain.com/notes/search/page/2 - shows page 2 of the above search