Record not found in table

There is no record in the table with id = 30 so the page throws an error: Record not found in table “recipes.” So I made a condition not to show the data if the record wasn’t found but then it can’t get the variables that are set in the method. I tried not showing the variables unless the id was set like this: if (isset($recipe->id)) but of course this can’t work…

I solved the problem like this:

$exists = $this->Recipes->exists(['id' => $id]);
if ($exists != true) {
$id = 31;
}

No, this didn’t solve the problem after all. Now when I click on the previous pagination link on the bottom of the page, it stays on the page number 31.

Added the following conditional to my previous pagination and a similar one to my next pagination and now it’s ok.

    <?php }
    else if ($recipe->id==31){
    echo $this->Html->link(__('<< previous', true), ['controller' => 'recipes', 'action' => 'view', $recipe->id = 29 ]);
    ?>

You’re hardcoding your templates to account for the fact that a particular ID doesn’t exist? Will this continue to grow whenever you delete another record? This is going to be a long-term maintenance nightmare.

The code in the controller applies to any records that were deleted, not just the record with an id of 30. So this will only have to be done once in the template.

$exists = $this->Recipes->exists(['id' => $id]);
if ($exists != true) {
$id = 31;	
}

But you’re right, Zuluru, it’s a nightmare anyway because the user will be sent to page number 31 every time a page/record is missing and there could be several missing pages/records. Hopefully I will come up with a better solution. Maybe I could just send the user to the previous page instead of always page 31.

What do you think would be a good solution to handle a missing page/record? I don’t need the code, I just want an idea about how this should be handled.

Maybe something like
$next_id = $table->find()->where(['id >' => $record->id])->order('id')->first()->id;

I implemented Zuluru’s code snippet and used the following in my controller

    public function view($id = null)
    {
					
	$exists = $this->Recipes->exists(['id' => $id]);
	$this->set('exists', $this->Recipes->exists(['id' => $id]));

	$next_id = $this->Recipes->find()->where(['id >' => $id ])->order('id')->first()->id;
	if ($exists != true) {
			$id = $next_id;		
		}

        $recipe = $this->Recipes->get($id, [
            'contain' => ['Users', 'Categories', 'Comments'],
        ]);
		$this->set('next_id', $this->Recipes->find()->where(['id >' => $recipe->id])->order('id')->first()->id);
		$this->set('prev_id', $this->Recipes->find('all', ['order'=>'id DESC'])->where(['id <' => $recipe->id])->first()->id);

I don’t like the condition that sets the $id as $next_id if the record doesn’t exist but I don’t know what to set it to instead.
In the template I’ve got:

<?php }
else if ($exists != true) {
echo $this->Html->link(__('<< previous', true), ['controller' => 'recipes', 'action' => 'view', $recipe->id = $prev_id ]);
?>

and

<?php 
} else if ($exists != true) {
echo $this->Html->link(__('next >>', true), ['controller' => 'recipes', 'action' => 'view', $recipe->id = $next_id ]);
?>

Skip all the stuff about exists. If somebody gets to a page that doesn’t exist, give them a proper error message. Use what you’ve got for sending the prev and next ids to the view to set up your pagination links. Oh, and you’ll need to do some extra to avoid errors when you’re viewing the first (no previous) or last (no next) record.

For the first and last recipes I show a grayed out element that doesn’t have a link so it looks like this:

<?php if ($recipe->id==1) {?>
<span style="color: #555;">&lt;&lt; previous</span>
<?php } ?>
<?php 
if ($recipe->id == $lastInsertID->id) { 
?>
<span style="color: #555;">next &gt;&gt;</span>
<?php } ?>

And I set the $lastInsertID in the controller like this:

//count doesn't work because one of the ids has been deleted so it returned one less than the last inserted id
//$this->set('lastInsertID',$this->Recipes->find()->count());	
$this->set('lastInsertID',$this->Recipes->find('all',['order'=>'id DESC'])->first());

Now I don’t want to display pages that have no content but there are several empty pages in a row and even though it goes to the next page it doesn’t account for all of the empty pages that there are. The field directions shouldn’t be empty.

<?php 
} else if ($exists != true || $recipe->directions == "" || $recipe->directions == NULL) {
echo $this->Html->link(__('next >>', true), ['controller' => 'recipes', 'action' => 'view', $recipe->id = $next_id ]);
?>

Untested, but should be very close.

public function view($id = null)
{
    try {
        $recipe = $this->Recipes->get($id, [
            'contain' => ['Users', 'Categories', 'Comments'],
        ]);
    } catch (RecordNotFoundException $ex) {
        // If the recipe doesn't exist, don't try to display anything. There's nothing useful to display! They never should have gotten to this page anyway.
        $this->Flash->info(__('Invalid recipe.'));
        return $this->redirect(['action' => 'index']);
    }

    // Get the previous and next records. If they don't exist (we're at the first or last one), these will be null. That's fine.
    $prev = $this->Recipes->find()->where(['id <' => $id ])->order(['id' => 'DESC'])->first();
    $next = $this->Recipes->find()->where(['id >' => $id ])->order(['id' => 'ASC'])->first();

    $this->set(compact('recipe', 'prev', 'next'));
}

Then in your template:

<?php if ($prev) {?>
<?= $this->Html->link(__('<< prev'), ['controller' => 'recipes', 'action' => 'view', $prev->id ]) ?>
<?php } else { ?>
<span style="color: #555;">&lt;&lt; previous</span>
<?php } ?>
<?php if ($next) {?>
<?= $this->Html->link(__('next >>'), ['controller' => 'recipes', 'action' => 'view', $next->id ]) ?>
<?php } else { ?>
<span style="color: #555;">next &gt;&gt;</span>
<?php } ?>

Thanks Zuluru for teaching me how compact can be used. I see now that I can use compact instead of $this->set.

Not so much “instead of” as “in conjunction with”. And sometimes, it’s better not to use it.