I have a while
loop that outputs three images onto an image preview board. This aspect is all working OK. I would like it so that if a preview board has no allocated images it still outputs the board component, but displays a message such as 'Add images to this board'.
In the code below, if the board preview component (the <figure>
element) is empty, it currently outputs an unwanted single empty <img>
tag. I thought I could fix this by changing this code block:
if ($imgcount < 3) {
echo "
<img src='{$dbImageFile}'>
";
}
to this:
// only allow 3 images per board
if ($imgcount < 3 && isset($dbImageFile)) {
echo "
<img src='{$dbImageFile}'>
";
}
// echo empty string if no image for this board
if ($imgcount < 3 && !isset($dbImageFile)) {
echo "";
}
...which I thought would output an empty string instead of the unwanted single <img>
tag if the board has no images allocated to it. This single image tag is missing the filename from its path (although I obviously want to stop this image tag being outputted completely)
And then at the end of the while
loop, add the following message when there are no images (this is currently commented out in the main code)
if ($imgcount == 0 ) {
echo "Add Images To This board";
}
In the MySQL code the boards_images
table is a linking/pivot table that holds the board id and a related image id for that board.
<?php
$s = "SELECT boards.board_name, boards.board_id, images.filename
FROM boards
LEFT JOIN boards_images on boards_images.board_id = boards.board_id
LEFT JOIN images on boards_images.image_id = images.image_id
WHERE boards.user_id = :user_id
ORDER BY boards.board_id";
$stmt = $connection->prepare($s);
$stmt -> execute([
':user_id' => $db_id // $_SESSION login variable
]);
$dbBoardname_last = '';
$imgcount = 0;
while ($row = $stmt->fetch()) {
$dbBoardId = htmlspecialchars($row['board_id']);
$dbBoardname = htmlspecialchars($row['board_name']);
$dbImageFile = htmlspecialchars($row['filename']);
// close the previousboard component <figure>
if($dbBoardname_last != '' && $dbBoardname != $dbBoardname_last) {
echo "
</figure>
";
}
//if the board name is the different to the previous one add the opening component tag
if($dbBoardname != $dbBoardname_last) {
//reset the image count for new boards
$imgcount = 0;
// output opening board component <figure>
echo "
<figure class='board-component'>
<h2>{$dbBoardname}</h2>
";
}
// only allow 3 images per board
if ($imgcount < 3) {
echo "
<img src='{$dbImageFile}'>
";
}
$imgcount =1;
//record the last board_name to check if a new board element should be created
$dbBoardname_last = $dbBoardname;
// *** IF NO IMAGES ARE PRESENT ECHO THE 'ADD IMAGES' MESSAGE ***
// if ($imgcount == 0 ) {
// echo "Add Images To this board";
// }
}
// close the last board component element
if ($dbBoardname_last != '') {
echo "
</figure>
";
}
?>
The board preview works as intended when the image count is 1, 2 or 3 images on a board preview, but shows the dreaded empty image tag when no images are present. Screenshot below.
CodePudding user response:
When a board has no images linked to it, MySQL populates the filename
value with NULL
. And, when a NULL
value is passed to the PHP htmlspecialchars()
function, it returns an empty string.
// when "filename" from the database is NULL, $dbImageFile is assigned an empty string.
$dbImageFile = htmlspecialchars($row['filename']);
Also PHP isset()
function returns true
when it is passed a variable that contains an empty string. Therefore the condition if ($imgcount < 3 && isset($dbImageFile)) {
writes the image tag when there is no image linked to the board.
When using htmlspecialchars()
you'll never get a NULL
, and MySQL always returns "filename" as a declared variable, even when it is assigned NULL
. That's why isset()
does not do what you expect with $dbImageFile
.
Either use the value, possibly containing NULL
, returned in the MySQL results set. $row['filename']
:
// only allow 3 images per board
if ($imgcount < 3 && isset($row['filename'])) {
echo "
<img src='{$dbImageFile}'>
";
}
...or, check for an empty string, "" !== $dbImageFile
:
// only allow 3 images per board
if ($imgcount < 3 && "" !== $dbImageFile) {
echo "
<img src='{$dbImageFile}'>
";
}
This is all you need. You don't need the second if
condition with another "less than 3 images written to the board" check, and if the $dbImageFile
is not set: !isset($dbImageFile)
:
$dbImageFile
in your code will always returntrue
when passed toisset()
(is set).$dbImageFile
in your code will always returnfalse
when passed to!isset()
(is not set).
CodePudding user response:
This is kind of tricky problem, because your query contains duplicates, in your case I would suggest to map the records at first and then looping them and print the HTML code
<?php
$boards = [];
while ($row = $stmt->fetch()) {
$boards[$row['board_id']] = $boards[$row['board_id']] ?? [];
$boards[$row['board_id']]['name'] = $row['board_name'];
$boards[$row['board_id']]['images'] = $boards[$row['board_id']]['images'] ?? [];
$boards[$row['board_id']]['images'][] = $row['filename'];
}
foreach ($boards as $board_id => $board) {
echo '<figure>';
echo $board['name'];
$images_length = count($board['images']);
for ($i = 0; $i < min($images_length, 3); $i ) {
echo "<img src='{$board['images'][$i]}'>";
}
if ($images_length === 0) {
echo "Add images to this board";
}
echo '</figure>';
}