Jan 19, 2015

Ketan Patel

Generate Previous Next Posts Link in CakePHP



There are many methods for retrieving your data in cakephp varying from simple find all to complex joins. CakePHP has many useful find type which makes the data retrieval process very easy without writing manual queries to fetch the data.


If you want to fetch the previous and next record of the id provided then in mysql you have to use the below queries,



Via two separate calls


For next:
        select * from posts where id = (select min(id) from posts where id > 12)
For previous:
        select * from posts where id = (select max(id) from posts where id < 12)


or in single call,

 

select * from posts 
where ( 
        id = IFNULL((select min(id) from posts where id > 12),0) 
        or  id = IFNULL((select max(id) from posts where id < 12),0)
      )


To achieve the same goal, CakePHP has one concept called 'neighbors' that we're going to see in detail - syntax , how to use , advantage etc. Using this concept you can show next previous link for posts.



Introduction


find('neighbors') is very similar to the simple find('first') query, only difference is it returns the row before and after the one you requested.


Example

Simple find('first') query,

$users= $this->User->find('first');
pr($users);die;

will return the following output.

Array
        (
            [User] => Array
                (
                    [id] => 1
                    [username] => test
                    [email] => test@test.com
                )
        )



Now, find('neighbors') query can be written as,

$users = $this->User->find('neighbors',array('field' => 'id', 'value' => 3));
pr($users);


which will return the following output.


Array
(
    [prev] => Array
        (
            [User] => Array
                (
                    [id] => 2
                    [username] => Second User
                    [email] => happy@test.com
                )
        )

    [next] => Array
        (
            [User] => Array
                (
                    [id] => 4
                    [username] => Fourth user
                    [email] => demo@test.com
                )
        )
)

as you can see that it returns the row before and after the one we requested(3 here).



Advantage


A well known simple blog example code for the view function is as below.

public function view($id = null) {
        if (!$id) {
            throw new NotFoundException(__('Invalid post'));
        }
        
        $post = $this->Post->findById($id);
        if (!$post) {
            throw new NotFoundException(__('Invalid post'));
        }
        $this->set('post', $post);
    }


and view.ctp file,


<!-- File: /app/View/Posts/view.ctp -->
<h1><?php echo h($post['Post']['title']); ?></h1>
<p><small>Created: <?php echo $post['Post']['created']; ?></small></p>
<p><?php echo h($post['Post']['body']); ?></p>


Now in this page if you want to view the details of any other record then you have two options,


(1) Put the back button to go back to the listing page and then view the desired record.
(2) Type the record's view URL directly in the address bar.


But both of the above cases are not good enough. Instead of this there should be two buttons for the Previous and Next using which you can switch the records view.


So this can be done using the neighbour concept. To implement this functionality make the following changes.

public function view($id = null) {
     if (!$id) {
      throw new NotFoundException(__('Invalid post'));
     }
    
     $post = $this->Post->findById($id);
     if (!$post) {
      throw new NotFoundException(__('Invalid post'));
     }
     $this->set('post', $post);

     // fetching the record's neighbors 
     $neighbors = $this->Post->find('neighbors',array('field' => 'id', 'value' => $id));
     $this->set('neighbors', $neighbors);
    }


and your view.ctp file ,

<!-- File: /app/View/Posts/view.ctp -->
<h1><?php echo h($post['Post']['title']); ?></h1>
<p><small>Created: <?php echo $post['Post']['created']; ?></small></p>
<p><?php echo h($post['Post']['body']); ?></p>

<!-- Generating Prev and Next buttons -->
<p>
 <span>
  <?php if(!empty($neighbors['prev'])){
   echo $this->Html->link('Prev',
   array('controller' => 'posts', 'action' => 'view', $neighbors['prev']['Post']['id'])); 
  } ?>
 </span>
 
 <span>
  <?php if(!empty($neighbors['next'])){
   echo $this->Html->link('Next',
  array('controller' => 'posts', 'action' => 'view', $neighbors['next']['Post']['id'])); 
  } ?>
 </span>
</p>


That's it!! you have working neighbors() concept implemented. Now you can switch the record view with single click.

Ketan Patel

About Ketan Patel -

I have developed a wide range of websites using CorePHP, Opencart, CakePHP and CodeIgniter including sites for startup companies and small businesses. Apart from my blogging life, I like to read Novels, Listening music and Net surfing.

Subscribe to this Blog via Email :