Как ВСТАВИТЬ несколько строк с несколькими значениями, но только для элементов, рядом с которыми установлены флажки

#php #mysql #insert

Вопрос:

Я кодирую инструмент дискографии для музыкальной базы данных.

Исполнители могут вставлять треки, синглы, EPS и альбомы в отдельные таблицы базы данных.

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

Это означает, что отдельные страницы треков могут иметь автоматически сгенерированный список ссылок на синглы, EPS и альбомы, на которых они появляются. Что делает навигацию по базе данных через веб-сайт намного более плавной.

Я дошел до того, что создаю инструмент для прикрепления любых существующих треков в базе данных для данного исполнителя на страницу альбома.

Я использую другую таблицу в базе данных под названием «trackconnections» для создания реляционных связей между идентификаторами дорожек из таблицы дорожек и идентификатором альбома из таблицы альбомов, с дополнительным столбцом под названием albumtracknum, доступным для вывода дорожек в правильном порядке при запросе на странице альбома.

Код инструмента находится за кнопкой с надписью «Прикрепить существующие треки к альбому». Код для этого инструмента выглядит следующим образом:

     if (isset($_POST['attachexistingtracktoalbum-submit'])) {
    
require "includes/db_connect.pdo.php";

$artistid = $_POST["artistid"];
$albumid = $_POST["albumid"];

echo '<strong>Select each track you would like to add to this album below and type in the track number you want it to have on the album in the box underneith the name of each selected track.</strong><br><br>';

$stmt = $pdo->query("SELECT * FROM track WHERE artist_id = '$artistid'
order by trackname");
while ($row = $stmt->fetch())
{           
    echo '<form action="includes/attachexistingtracktoalbum.inc.php" method = "post">';
    echo '<div class="checkbox">';
    echo '<label>';
    echo "<input type='checkbox' name='trackid[]' value='".$row['id']."' />";
        echo '<span class="cr"><i class="cr-icon glyphicon glyphicon-ok"></i></span>';
    echo ' '.$row['trackname'];
    echo '</label>';
    echo "<br><label for='albumtracknum'>Track number:</label><br>
    <input type='text' name='albumtracknum[]'>
    <input type='hidden' name='albumid[]' value='".$albumid,"'>
    <br><br>";
    echo '</div>';

}
?>
  <input type="hidden" name="albumidforreturn" value="<?php echo $albumid;?>">
  <button type="submit" name="attachexistingtracktoalbum-submit">Attach track(s) to album</button>
  
<?php }
else {
header("Location: /index.php");
 exit();
}?>
 

(NB: The post data here is not sanitised for the sql query as it has been passed along in a hidden form from the original album page)

This generates a page with all track names for the current artist available on a list with checkboxes, with each track name being followed by a data entry box to enter the track number for the album being added to.

Submission of the form then hands off to the following include code:

     if (isset($_POST['attachexistingtracktoalbum-submit'])) {

require "db_connect.pdo.php";
 
 $albumid = implode(',',$_POST['albumid']);
 $trackid  = implode(',',$_POST['trackid']);
 $albumtracknum  = implode(',',$_POST['albumtracknum']);
 $albumidforreturn = $_POST['albumidforreturn'];

// echo 'albumid: '.$albumid.'<br>';
// echo 'trackid: '.$trackid.'<br>';
// echo 'albumtracknum: '.$albumtracknum.'<br>';
 
  $sql = "INSERT INTO trackconnections (albumid, trackid, albumtracknum) VALUES (?,?,?);";
  $stmt= $pdo->prepare($sql);
  $stmt->execute([$albumid,$trackid,$albumtracknum]);
    header("Location: ../albumdetail.php?albumid=$albumidforreturn");
    exit();
}
else {
header("Location: ../index.php");
 exit();
}
 

(NB: The commented out echos are there to test what the output is from the previous form)

The 2 problems I am having are that my ‘Attach existing tracks to album’ form submit:

1. Passes on too much data.

The generated form should only pass on the track ids, album number, and track numbers that have had their checkboxes ticked. For insertion into the ‘trackconnections’ table.

Instead it narrows down the ticked checkbox track ids only and then creates comma separated values for every available track to select, rather than just those actually selected.

Which leads to annoying outputs such as the following when passing on data from form to include:

 albumid: 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
trackid: 30,14
albumtracknum: ,2,3,,,,,,,,,,,,,,,,,,,,,
 

Where it should only read as:

 albumid: 4,4
trackid: 30,14
albumtracknum: 2,3
 

Having too much data get passed through means that the row inserts won’t be correct on multiple INSERTS once I do get this working, as they won’t align with one another in the correct order.

2. The include only INSERTS 1 row to the ‘trackconnections’ table.

It seems I am misunderstanding how to add multiple rows to the database with my code here.

As having multiple checkboxes ticked on my ‘Attach existing tracks to album’ form only inserts 1 single row to the database on submission of the form each time.

Consistently the only track that gets added to the ‘trackconnections’ table is the first track with its checkbox ticked and, because of issue no. 1 above, the albumtracknum is always 0 unless I type a number into the first albumtracknum box on the available checklist.

I need to make tweaks to this code so that both problem 1 and 2 are addressed together, meaning that ticking the checkboxes amp; adding track numbers into each box following the track names actually adds multiple rows to the database along with their corresponding album track numbers.

I hope someone can help.

EDIT TO SHOW REFINED AND WORKING CODE:

New code for checkbox and textbox sections —

 if (isset($_POST['attachexistingtracktoalbum-submit'])) {
    
require "includes/db_connect.pdo.php";

$artistid = $_POST["artistid"];
$albumid = $_POST["albumid"];

echo '<strong>Select each track you would like to add to this album below and type in the track number you want it to have on the album in the box underneith the name of each selected track.</strong><br><br>';

$stmt = $pdo->query("SELECT * FROM track WHERE artist_id = '$artistid'
order by trackname");

echo '<form action="includes/attachexistingtracktoalbum.inc.php" method = "post">';

while ($row = $stmt->fetch())
{           
    
    echo '<div class="checkbox">';
    echo '<label>';
    echo "<input type='checkbox' name='trackid[]' value='".$row['id']."' />";
        echo '<span class="cr"><i class="cr-icon glyphicon glyphicon-ok"></i></span>';
    echo ' '.$row['trackname'];
    echo '</label>';
    echo "<br><label for='albumtracknumber'>Track number:</label><br>
    <input type='text' name='albumtracknumber_".$row['id']."'>
    <input type='hidden' name='albumid[]' value='".$albumid,"'>
    <br><br>";
    echo '</div>';

}
?>
  <input type="hidden" name="albumidforreturn" value="<?php echo $albumid;?>">
  <button type="submit" name="attachexistingtracktoalbum-submit">Attach track(s) to album</button>
  </form>
  
<?php }
else {
header("Location: /index.php");
 exit();
}
 

Новый код для обработки включенной ВСТАВКИ —

     if (isset($_POST['attachexistingtracktoalbum-submit'])) {

    require "db_connect.pdo.php";
     
     $albumid = implode(',',$_POST['albumid']);
     $trackid  = implode(',',$_POST['trackid']);
     $albumidforreturn = $_POST['albumidforreturn'];
     
foreach($_POST['trackid'] as $trackidloop) {
    
$albumtracknum = $_POST["albumtracknumber_{$trackidloop}"];

$sql = "INSERT INTO trackconnections (albumid, trackid, albumtracknum) VALUES (?,?,?);";
      $stmt= $pdo->prepare($sql);
      $stmt->execute([$albumid,$trackidloop,$albumtracknum]);
}
        header("Location: ../albumdetail.php?albumid=$albumidforreturn");
        exit();
    }
    else {
    header("Location: ../index.php");
     exit();
    }
 

Комментарии:

1. Оглядываясь назад, я задаюсь вопросом, не совершил ли я ошибку, взорвав массив. Массив может действительно потребоваться для отправки нескольких строк… Как бы то ни было, я слишком устал, чтобы смотреть на это сегодня вечером. Я ложусь спать в надежде, что утром появится полезный ответ.

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

3. Я не использую значения, разделенные запятыми, в этом коде не требуется редактирование существующих записей. Я вставляю новые внешние ключи в таблицу с именем «trackconnections» для создания соединений. Вот почему мне нужна отдельная строка для каждого нового соединения.

4. Запятые выше предназначены для добавления нескольких отдельных строк одновременно, а не для размещения всех запятых в одной строке. Извините, если это было неясно.

Ответ №1:

Это не полное решение, но я вижу некоторые проблемы: вы просматриваете дорожки и создаете новую форму для каждой из них. Первая проблема заключается в том , что у вас отсутствует закрывающий тег формы. Я предполагаю, что браузер автоматически создает его, когда видит следующий тег запуска формы. ?? Вот почему вы получаете только один флажок «Опубликовано». Я бы поместил все флажки отслеживания в единую форму. Тогда опубликованный массив trackid[] будет содержать все проверенные элементы.

[РЕДАКТИРОВАТЬ после вашего комментария: Скрытые поля albumid[] отображают весь массив, в то время как флажки trackid[] отображают только фактические флажки (спецификация HTML).

Вместо того, чтобы использовать albumid [], вы могли бы объединить идентификатор трека и идентификатор альбома для значения флажка, а затем разобрать их отдельно, когда вы обрабатываете сообщение: $value = $row['id']. ',' . $row['albumid'];
echo "<input type='checkbox' name='trackid[]' value='".$value."' />";

КРОМЕ того, SQL «ВСТАВИТЬ В (..) .. ЗНАЧЕНИЯ (…)» вставляет только одну строку.
Легко выполнить этот SQL в цикле для всех отмеченных флажков.
foreach($_POST['trackid'] as $value) {
// parse the $value...
// SQL Insert...
}

ПРАВКА 2: Из моего собственного комментария: Как и скрытые поля, массивы входных (текстовых) полей также отображают весь массив (с пустыми значениями для пустых входных данных). (Опять же, это не PHP, это стандарт веб-браузера, позволяющий размещать только отмеченные флажки и переключатели. Но ВСЕ текстовые и скрытые вводы публикуются.) Поэтому в вашем примере вам нужно закодировать механизм, чтобы узнать, какое текстовое поле соответствует каждому флажку. Быстро и грязно…Вы можете добавить индекс строки (0,1,2,3…) в качестве другого числа, разделенного запятыми, в значения флажков, тогда у вас будет индекс в массиве опубликованных текстовых полей. В качестве альтернативы вы можете назвать текстовые ' .. name="textinput_' . $row['trackid'] . '" ...' поля (не массив), а затем после публикации прочитать их в цикле foreach с помощью
$val = $_POST["textinput_{$trackid}"];

Комментарии:

1. Массив trackid[] уже содержит все проверенные элементы при отправке. Это единственный проход, который действительно работает так, как задумано. Это только части формы albumid и albumtracknum, которые не соблюдают флажки.

2. Хороший момент в теге закрытия формы, хотя, с моей стороны, небрежно, обновится. Но это не нарушает функциональность самой формы.

3. А, ладно. В массиве «скрытых» полей всегда отображаются все элементы массива, в то время как флажки отображают только флажки. HTML — «функция».

4. Я изменил свой ответ после того, как лучше понял проблему 🙂

5. Итак, с циклом foreach у меня теперь есть несколько треков, и их идентификатор альбома импортируется в мою таблицу trackconnections. Все это хорошо. Однако фактическое поле albumtracknum по-прежнему обращает внимание только на первое введенное значение. Поэтому, если я отмечу флажки 1,2 и 3 и введу номера дорожек под каждым из них, он вставит их все в качестве номера в поле ввода под флажком 1. Игнорирует все остальные номера дорожек.