Ray
Ray

Reputation: 1145

CakePHP 3 How to use next and prev for view action

I am trying to integrate next and prev buttons in my view page for CustomersController. In my next button, I am trying to add a link that will take to next record from the table. Same for prev that will get the previous record from the table. I tried below pagination, but when I click next, it takes me to http://localhost/path/customers/view/1?page=2 link, I want to find away that will take me to next record like this http://localhost/path/customers/view/2

// Shows the page numbers
<?= $this->Paginator->numbers() ?>

// Shows the next and previous links
<?= $this->Paginator->prev('« Previous') ?>
<?= $this->Paginator->next('Next »') ?>

// Prints X of Y, where X is current page and Y is number of pages
<?= $this->Paginator->counter() ?>

I also tried this <?= $this->Paginator->numbers(['first' => 2, 'last' => 2]); ?>.

Upvotes: 1

Views: 986

Answers (2)

Eymen Elkum
Eymen Elkum

Reputation: 3141

I found this solution, it worked fine to me, I hope it to help you:

//controller view action 
public function view($id = null)
{
    $ids = Cache::read('items_ids');
    if (empty($ids)) {
        $ids = $this->Items->find('list')->toArray();
        Cache::write('items_ids', $ids);
    }
    /*
     * $ids here must be something like this:

     Array
        (
            ............
            [GS00001] => Item 1
            [GS00003] => Item 2
            ..........
        )

    */
    //pr($ids);die; //this for debug


    //seek to the item with id = $id
    while (key($ids) !== $id) next($ids);

    if($next = next($ids)){
        $next = [
            'id' => key($ids),
            'name' => current($ids)
        ];
    }else{
        end($ids);
    }

    prev($ids);
    if($prev = prev($ids)){
        $prev = [
            'id' => key($ids),
            'name' => current($ids)
        ];
    }
    //pr(compact(['next','prev']));die;
    /*

    $next and $prev here:

    If first:
    Array
    (
        [next] => false
        [prev] => Array
            (
                [id] => GS00264
                [name] => Last Item
            )

    )

    If last:
    Array
    (
        [next] => Array
            (
                [id] => GS00003
                [name] => First Item
            )

        [prev] => false
    )

     * */


    $item = $this->Items->get($id, [
        'contain' => ['MenuGroups', 'Orders']
    ]);
    $this->set(compact(['item','next','prev','ids']));
    $this->set('_serialize', ['item','next','prev','ids']);
}

and in the view template simply write:

    <ul>
        <li><?= $this->Html->link('<< ' . $prev['name'],['action'=>'view',$prev['id']]); ?></li>
        <li><?= $this->Html->link($next['name'] . ' >>',['action'=>'view',$next['id']]); ?></li>
    </ul>

and in Bootstrap.css case:

<nav>
    <ul class="pager">
        <li class="previous <?= ($prev) ? '' : 'disabled' ?>">
            <?= $this->Html->link('<span aria-hidden="true">&larr;</span> ' . $prev['name'], ['action' => 'view', $prev['id']], ['escape' => false]); ?>
        </li>
        <li class="next <?= ($next) ? '' : 'disabled' ?>">
            <?= $this->Html->link($next['name'] . ' <span aria-hidden="true">&rarr;</span>', ['action' => 'view', $next['id']], ['escape' => false]); ?>
        </li>
    </ul>
</nav>

Note: you are free to use Cache or not, but I found it useful in the case you will need this query every time, you can manually refresh the cache key in the Entity afterSave

public function afterSave(Event $event, Item $entity, $options)
{
    Cache::delete('items_ids');
}

Upvotes: 1

Eymen Elkum
Eymen Elkum

Reputation: 3141

We can use foreach instead of next and prev:

public function view($id = null)
{
    $ids = Cache::read('items_ids');
    if (empty($ids)) {
        $ids = $this->Items->find('list')->toArray();
        Cache::write('items_ids', $ids);
    }
    /*
     * $ids here must be something like this:

     Array
        (
            ............
            [GS00001] => Item 1
            [GS00003] => Item 2
            ..........
        )

    */
    //pr($ids);die; //this for debug


    //seek to the item with id = $id
    $found = $next = $prev = false;
    foreach ($ids as $key => $value) {
        //pr($key);
        if($found){
            $next = [
                'id'   => $key,
                'name' => $value
            ];
            break;
        }
        if ($key == $id) {
            $found = true;
        } else {
            $prev = [
                'id'   => $key,
                'name' => $value
            ];
        }
    }
    //pr(compact(['next','prev']));die;
    /*

    $next and $prev here:

    If first:
    Array
    (
        [next] => false
        [prev] => Array
            (
                [id] => GS00264
                [name] => Last Item
            )

    )

    If last:
    Array
    (
        [next] => Array
            (
                [id] => GS00003
                [name] => First Item
            )

        [prev] => false
    )

     * */


    $item = $this->Items->get($id, [
        'contain' => ['MenuGroups', 'Orders']
    ]);
    $this->set(compact(['item', 'next', 'prev', 'ids']));
    $this->set('_serialize', ['item', 'next', 'prev', 'ids']);
}

Upvotes: 0

Related Questions