PHP: как отобразить несколько записей таблицы MySQL в строке таблицы HTML с помощью MySQLi

Я хотел бы отобразить группу элементов в строке в php из базы данных mysql. Я уже сделал это, но мои данные появляются в одной длинной колонке. Я хотел бы, чтобы каждый новый элемент появлялся один рядом с другим.

Вот скриншот, что я получаю. Я бы хотел, чтобы первый был рядом со вторым:

http://img.ruphp.com/database/Capture.PNG?dl=0

Вот мой код:

<?php require_once 'core/init.php'; include 'includes/navigation.php'; $sql = "SELECT * FROM interviews WHERE featured = 1"; $featured = $db->query($sql); <html> 

enter code here enter code here

  <link href="http://localhost/menu/css/academy.css" rel="stylesheet" `enter code here`type="text/css" /> 

  <?php while($product = mysqli_fetch_assoc($featured)) : ?> <table> <tr> <th> <div id="element1"></div> <div id="content1"> <img src="<?= $product['image']; ?>" alt="<?= $product['title']; ?>"> <h4><?= $product['title']; ?></h4> <hr> <p class="description"><?= $product['description']; ?></p> <!--------BUTTON 3--------> <div id="hovers"> <a href="#" class="button"> <span class="contentbut"> Read More</span> </a> </div> </th> </tr> </table> <?php endwhile; ?> </div> </div> 

Пожалуйста помоги.

Спасибо!

Введение

Примечание . В этом ответе подробно описывается создание многозадачных записей . Тем не менее, этот ответ может быть изменен, чтобы обеспечить компоновку с одной записью на одну строку .

Разделение проблем поможет вам написать более чистый код. Разделение проблем упростит работу с вашим кодом. Чистый код слабо связан , не загружается встроенными зависимостями. Чистый код определяет его зависимости в сигнатурах функций и конструкторах классов с ожиданием того, что эти потребности будут выполнены извне. Чистый код имеет плотное сцепление . Это означает, что функции / методы имеют одну задачу, а классы имеют одну цель. Чистый код часто отражается в задаче, которая была разбита и уточнена (но не всегда). Чистый код идеален, к чему я стремлюсь, но никто не идеален.

Попытайтесь придумать, как получить SQL и PHP из ваших HTML- файлов. Интерполяция переменных и отображение результатов результатов только могут сделать ваш HTML намного легче читать. Хорошая структура HTML тоже.

Очень возможно выполнение задачи динамического построения <table> на основе результатов SQL-запроса. В конце концов, вы можете использовать CSS и divs для определения стиля и реакции. Этот код может быть изменен для достижения этого (в конце концов, вы просто будете складывать ящики в строки).

В конечном итоге создание класса ООП (с пользовательскими пространствами имен) было бы прекрасно для модуляции кода и получения подавляющего большинства ваших символов (имена переменных и т. Д.) Из глобального пространства имен .


Прежде чем мы перейдем: php.ini: include_path

Вы хотите настроить логическую архитектуру каталога для своего проекта?

Установите include_path внутри php.ini .

Если вы ищете свой php.ini для параметра include_path , вы можете установить его в один каталог или любую группу соответствующих каталогов. Таким образом, вы можете упорядочить свои файлы в каталогах так, как вы этого хотите, и ваши инструкции include , include_once , require и require_once все равно найдут файлы, которые они хотят импортировать. Вам не нужно вводить абсолютные пути, такие как /dir/dir/file.php или относительные пути, такие как ../../core/database.php . В обоих случаях вы можете просто указать имя файла.

Пример:

 include 'file.php'; //Finds the file if it is in the include_path. require 'database.php'; //Finds the file if it is in the include_path. 

Примечание . Храните файлы библиотеки и другие чистые файлы кода PHP (и т. Д.) Из веб-сайта или любых общедоступных каталогов. Держите их логически над веб-корнем. Установите include_path чтобы вам не приходилось постоянно делать ../../blah/foo все время.


Задания

1 ) Сначала создайте функцию для получения экземпляра объекта mysqli_result .

 /** * Returns a string, or * throws an UnexpectedValueException, otherwise. */ function isString($string) { if (!is_string($string)) { throw new UnexpectedValueException("$string must be a string data type."); } return $string; } /** * Returns a mysqli_result object, or throws an `UnexpectedValueException`. * You can reuse this for other SELECT, SHOW, DESCRIBE or EXPLAIN queries. */ function getMySQLiResult(MySQLi $db, $sql) { $result = $db->query(isString($sql)); if (!($result instanceof mysqli_result)) { throw new UnexpectedValueException("<p>MySQLi error no {$db->errno} : {$db->error}</p>"); } return $result; } 

2 ) Во-вторых, создайте функцию для размещения вашего SQL и вызовите getMySQLiResult ().

 /** * Make sure you can get the data first. * returns a mysqli_result object. */ function getInterviews(MySQLi $db) { $sql = "SELECT * FROM `interviews` WHERE `featured` = 1"; return getMySQLiResult($db, $sql); } 

3 ) Создайте функцию для создания ячейки таблицы ( <td></td> ) и ее содержимого. Поместите все HTML или данные, которые вам нужно повторить для каждой записи .

 /** * Returns one database table record a table data cell. */ function buildCell(array $record) { return "<td>\n". '<img src="' .$record['image']. '" alt="' .$record['title']. '">' ."\n". '<h4>' .$record['title']. '</h4>' . "\n" . '<hr>' . "\n" . '<p class="description">' .$record['description']. '</p>' . "\n" . '<div id="hovers"> <a href="#" class="button"> <span class="contentbut">Read More</span> </a> </div>' . "\n </td>\n"; } 

4 ) Создайте функцию для построения строк таблицы. Будьте осторожны с частичными рядами. 🙂

Во-первых , небольшая вспомогательная функция.

 /** * Returns one <tr></tr> element. Helper. */ function makeTr($tds) { return "<tr>\n" .isString($tds). "\n</tr>"; } 

Во-вторых , реальная сделка.

 function buildTableRow (array $tableRow) { return makeTr(buildCell($tableRow)) . "\n"; //Done! } /** * Returns a string of multiple <tr></tr> elements, * $maxRecords per row. */ function buildTableRows(array $tableRows, $numRecords, $maxPerRow) { $rows = []; // Holds finished groups of <tr>s $row = ''; // Temporary variable for building row of <td>s $numCells = 0; // Number of cells currently in a row of <td>s. $numRows = (int)($numRecords / $maxPerRow); //Rows to make. $numStragglers = $numRecords % $maxPerRow; // Extra <td>s, partialRow. if ($numStragglers !== 0) { //Check if extra row is needed. $numRows += 1; } foreach ($tableRows as $record) { $row .= buildCell($record); ++$numCells; if ($numCells === $numRecords) { // Builds partial, last row, if needed. $rows[] = makeTr($row); break; // Done! } if ($numCells === $maxPerRow) { // Builds full row. $rows[] = makeTr($row); // Save the row. $numCells = 0; // Start cell counter over. $row = ''; // Start a new row. } } if(count($rows) !== $numRows) { //Verify all rows were created. throw new RuntimeException("Rows (<tr>) for all records were not created!"); } return implode("\n", $rows) . "\n"; //Return all rows as a string. } 

5 ) Сделайте функцию, которая выплескивает HTML-код, который вам нужен на вашей странице. В этом случае вам нужна только одна (1) подстановка, которая появится в HTML.

 /** * returns a set of HTML table rows (<tr></tr>) to fill a <tbody>. * or, returns an alternative message. */ function drawInterviews(MySQLi $db, $maxPerRow) //PDO is recommened. Dependency injection. { $defaultMessage = "<tr>\n<td>There are no featured interviewers.<td>\n<\tr>\n"; try { if (!is_int($maxPerRow) || $maxPerRow < 1) { throw new RangeException("The number of interviews per row must be an integer equal to 1, or greater than 1."); } //Make a robust connection sequence, or pass it in like above. //$db = new mysqli('host', 'user', 'password', 'dbname'); $result = getInterviews($db); $numRecords = result->num_rows; if ($numRecords < 1) { return $defaultMessage; } if ($numRecords === 1) { return buildTableRow($result->fetch_assoc()); } return buildTableRows($result->fetch_all(), $numRecords, $maxPerRow); } catch (Exception $e) //Something went wrong with the query. error_log($e->getMessage()); } finally { //PHP 5.5+ $result->free(); } return $defaultMessage; } 

6 ) Теперь у вас хорошая структура HTML <table> . Требуется только одна интерполяция. Предполагая три <td> s (записи) в строке …

В любом случае, если вы хотите таблицу, поместите копию этой таблицы «скелет» внутри academytest.php , где-то между заголовком и нижним колонтитулом (т. academytest.php Основным <body> документа HTML).

 <table> <caption>Featured Interviewers</caption> <!-- Centers above table. --> <thead> <tr> <!-- If needed. --> <th>Heading1</th> <!-- If needed. --> <th>Heading2</th> <!-- If needed. --> <th>Heading3</th> <!-- If needed. --> </tr> </thead> <tfoot></tfoot> <!-- If needed. Yes, it goes after <thead>. --> <tbody> <!-- <div id="element1"></div> --> //What goes between here? <!-- <div id="content1"> --> //What's this? <?= drawInterviews($db, 3); ?> <!-- Dependency injection. --> </tbody> </table> 

Все это можно сделать более модульным и многоразовым (объектно-ориентированным, четным).


Обновить:

Основываясь на вашем коде Dropbox …

academytest.php

1 ) Лучше всего создать отдельный PHP-файл с именем tbodyFiller.php или что-то в этом роде. Поместите все функции в этот файл, за исключением getInterviews() и drawInterviews() которые войдут в academyLibray.php , isString() которые перейдут в getMySQLiResult() и getMySQLiResult() которые getMySQLiResult() в database.php (ранее init.php ).

Начало academytest.php должно выглядеть так:

 <?php // academytest.php require '../../includes/library.php'; //For now, put generic helper functions here. Group them, later. require_once '../../core/database.php'; //Formerly, init.php. Put getMySQLiResult() in here. require '../../includes/academyLibrary.php'; //Put the two "interview" functions here. $db = getMySQLi(); //Many things are dependent on this being here. require '../../includes/navigation.php'; /***************** DELETE THESE LINES *****************/ //$sql = "SELECT * FROM interviews WHERE featured = 1"; //$featured = $db->query($sql); /******************************************************/ 

В нижнем колонтитуле academytest.php закройте соединение с вашей базой данных.

 <!-- ------FOOTER------ --> <?php include '../../includes/footer.php'; $db->close(); //Ensures $db is available to use in the footer, if necessary. ?> 

library.php

Начало library.php должно выглядеть так:

 <?php // library.php /** * Returns a string, or * throws an UnexpectedValueException, otherwise. */ function isString($string) { if (!is_string($string)) { throw new UnexpectedValueException("$string must be a string data type."); } return $string; } 

Я думаю, что init.php следует назвать database.php . Вы можете научиться использовать объектно-ориентированный конструктор (используя new ) последовательность с проверкой ошибок на досуге. В конце концов, вы захотите узнать PDO .

Кроме того, создайте отдельный файл для хранения ваших учетных данных. Прямо сейчас, это лучше, чем жесткое их кодирование в функции getMySQLi() .

dbCreds.php

 <?php // dbCreds.php $host = ''; //IP or DNS name: string. $username = ''; //Your account: string. $passwd = ''; //The password: string. $dbname = ''; //The database you want to work with: string. //************************************************************************* //$port = '3306'; //Un-comment and change only if you need a differnt TCP port. //Also, you would need to add a $port as your last argument in new MySQLi(), //in the getMySQLi() function. 

database.php

 <?php // database.php /** * Returns a mysqli_result object, or throws an `UnexpectedValueException`. * You can reuse this for other SELECT, SHOW, DESCRIBE or EXPLAIN queries. */ function getMySQLiResult(MySQLi $db, $sql) { $result = $db->query(isString($sql)); if (!($result instanceof mysqli_result)) { throw new UnexpectedValueException("<p>MySQLi error no {$db->errno} : {$db->error}</p>"); } return $result; } function getMySQLi() //This can be improved, but that's not the issue right now. { require_once 'dbCreds.php'; //Choose your own file name. Do not put in public directory. $db = new mysqli($host, $username, $passwd, $dbname); //$port would be next. if(!($db instanceof MySQLi)){ throw new UnexpectedValueException("A MySQLi object was not returned during your connection attempt."); } if(isset($db->connect_error)){ throw new UnexpectedValueException("The database connection was not established. {$db->connect_errno} : {$db->connect_error}"); } return $db } //Using the object form of MySQLi object has side benenfits. 

academyLibrary.php

Начало academyLibrary.php должно выглядеть так:

 <?php // academyLibrary.php require 'tbodyFiller.php'; //Put all but four functions in here. function getInterviews(MySQLi $db) { $sql = "SELECT * FROM `interviews` WHERE `featured` = 1"; return getMySQLiResult($db, $sql); } /** * Comments //etc... */ function drawInterviews(MySQLi $db, $maxPerRow) { //The code, etc ... } 

Если вы не настроили свой include_path внутри php.ini , убедитесь, что academyLibrary.php и tbodyFiller.php находятся в одном каталоге.


navigation.php

Мы собираемся заменить процедурные формы работы с MySQL объектно-ориентированными. Это просто, и нам не нужно сильно меняться. Я не буду заменять ваши циклы или запросы в настоящее время, но мой совет – выйти из привычки помещать петли PHP и SQL непосредственно в ваш HTML. Найдите способ использования функции или метода, например, для таблицы в academytest.php . К этому времени у вас должно быть достаточно примеров. 🙂

Рефакторинг

Я потратил некоторое время на реорганизацию этого файла. Вот что у меня на вершине. Еще раз , возможно, вы захотите создать еще один PHP-файл, например navLibrary.php , и поместить в него эти функции. В этом случае вы замените все функции, указанные ниже, на одну строку, для которой require 'navLibrary.php'; , Естественно, этот способ импорта кода может зависеть от настройки вашего include_path внутри php.ini .

 <?php // navigation.php function getPqueryMainData(MySQLi $db) { $sql = "SELECT * FROM `mainmenu` WHERE `parent` = 0"; //pqueryMain return getMySQLiResult($db, $sql); } function getPqueryData(MySQLi $db) { $sql = "SELECT * FROM `categories` WHERE `parent` = 0"; //pquery return getMySQLiResult($db, $sql); } function getCquery1Data(MySQLi $db) { $sql = "SELECT * FROM `categories` WHERE `parent` = 1"; //cquery1 return getMySQLiResult($db, $sql); } function getCquery2Data(MySQLi $db, $int) { $sql = "SELECT * FROM `categories` WHERE `parent` = '$int'"; //cquery2 return getMySQLiResult($db, $sql); } //Consider doing at most 3 queries early on. //Consider using better names for your variables. //I get that 'p' means "primary", and 'c' means "child", but come on. :-) $pqueryMain = getPqueryMainData($db); $pquery = getPqueryData($db); $cquery1 = getCquery1Data($db); $cquery2 = null; 

В коде есть несколько проблем, например:

  • Вы создаете новую таблицу в каждой итерации цикла while() .
  • Вы используете те же идентификаторы div , element1 и content1 для всех ваших строк таблицы. Вместо этого используйте class . Однако, исходя из вашего вопроса,

    Я хотел бы, чтобы каждый новый элемент появлялся один рядом с другим.

    Вы можете использовать атрибуты id там, но вы должны взять все <table> ... <div id="content1"> и <div id="hovers"> ... </table> из while() . И, конечно же, изменить id="hovers" на class="hovers" и соответствующий CSS соответственно.

Таким образом, код решения будет выглядеть так:

 <table> <tr> <div id="element1"></div> <div id="content1"> <?php while($product = mysqli_fetch_assoc($featured)){ ?> <td> <img src="<?= $product['image']; ?>" alt="<?= $product['title']; ?>"> <h4><?= $product['title']; ?></h4> <hr> <p class="description"><?= $product['description']; ?></p> <!--------BUTTON 3--------> <div class="hovers"> <a href="#" class="button"> <span class="contentbut"> Read More</span> </a> </div> </td> <?php } ?> </div> </tr> </table> 

Обновление (1):

Из комментария OP ,

Я пытаюсь провести 3 интервью подряд и несколько строк с интервью.

Решение состояло бы в том, чтобы иметь три ячейки таблицы в каждой строке,

 <table> <div id="element1"></div> <div id="content1"> <tr> <?php $counter = 1; while($product = mysqli_fetch_assoc($featured)){ if($counter % 4 == 0){ echo '</tr><tr>'; } ++$counter; ?> <td> <img src="<?= $product['image']; ?>" alt="<?= $product['title']; ?>"> <h4><?= $product['title']; ?></h4> <hr> <p class="description"><?= $product['description']; ?></p> <!--------BUTTON 3--------> <div class="hovers"> <a href="#" class="button"> <span class="contentbut"> Read More</span> </a> </div> </td> <?php } ?> </tr> </div> </table>