简体   繁体   中英

How to generate dynamic content from two tables with PHP

Solved!! Thanks, guys. This was my first question on here. Let me know if I'm not formatting this correctly or something. Here's my finished code:

Answer:

$sql = 'SELECT a.*, GROUP_CONCAT(t.name) as track_name FROM albums AS a LEFT JOIN tracks AS t ON a.album_id = t.album_id GROUP BY a.album_id';

foreach ($conn->query($sql) as $row) { ?>
    <div class="container">
     <div class="row">
     <div class="col-6">
      <img src="../images/<?= $row['album_cover']?>" alt="Card image cap" style="width:100%;">
    <!--shadow-->
      <div class="shadow-lg p-3 mb-5 bg-white rounded">
      <div class="card-body" style="padding-left:10px;">
      <h4 class="card-title"><?= $row['album_name'] ?></h4>


    <b><?= print_r($row['album_name'] . ' (' . $row['record_label'] . ') (' . $row['year_released'] . ')', true); ?><br><br></b>
     <ul class="list-group list-group-flush">
        <?php
        $tracks = explode(",", $row['track_name']);
        $numTracks = count($tracks);
        $i = 0;
        while ($i < $numTracks) { ?>
        <li class="list-group-item">
            <?php 
            echo $tracks[$i]; 
            $i++;
            ?>
            </li>
        <?php } ?>
      </ul>
     </div>
    </div>
    </div>
    </div>
    </div>
<?php } ?>

Question (Solved): I am working on a project for school. I have to revamp an existing discography site (Queen) using php. The part I'm stuck on now is pulling album info from a database and using it to populate the page with each album along with the track names for the album. I have my album info in one table called albums, and all the tracks for every album in another table called tracks, with album_id as a foreign key.

I can get to the point where it's generating the album title from the album table in my database, but I have no idea how to get the tracks for each album.

This is my SQL query:

$sql = '
SELECT a.album_id
     , a.album_name
     , a.year_released
     , a.record_label
     , a.album_cover
     , t.name
     , t.album_id
  FROM albums AS a 
  LEFT 
  JOIN tracks AS t 
 USING (album_id)
';

And here is the part in that is supposed to generate the albums:

<?php
foreach ($conn->query($sql) as $row) { ?>
     <div class="col-6">
      <img src="../images/<?= $row['album_cover']?>" alt="Card image cap" style="width:100%;">
    <!--shadow-->
      <div class="shadow-lg p-3 mb-5 bg-white rounded">
      <div class="card-body" style="padding-left:10px;">
      <h4 class="card-title"><?= $row['album_name'] ?></h4>


    <b><?= print_r($row['album_name'] . ' (' . $row['record_label'] . ') (' . $row['year_released'] . ')', true); ?><br><br></b>
     <ul class="list-group list-group-flush">
        <li class="list-group-item">Innuendo</li>  <!-- these are just placeholders for the tracks because I don't know what to do here! -->
        <li class="list-group-item">I'm Going Slightly Mad </li>
        <li class="list-group-item">Headlong</li>
        <li class="list-group-item">I Can't Live With You</li>
        <li class="list-group-item">Don't Try So Hard </li>
        <li class="list-group-item">Ride The Wild Wind</li>
        <li class="list-group-item">All God's People</li>
        <li class="list-group-item">These Are The Days Of Our Lives</li>
        <li class="list-group-item">Delilah</li>
        <li class="list-group-item">The Hitman</li>
        <li class="list-group-item">Bijou</li>
        <li class="list-group-item">The Show Must Go On </li>
      </ul>
     </div>
    </div>
    </div>
    <?php
    }
?>

As it stands, my page is being populated by the same album info over and over because the foreach is iterating through every row in both tables. How do I generate specific tracks based on unique albums?

You call $conn->query($sql) every loop which will return the whole result set again. Also, use while loop like below, not foreach loop since $conn->query() return a mysqli_reuslt object, not an array.

$sql = 'SELECT a.album_id, a.album_name, a.year_released, a.record_label, a.album_cover, t.name, t.album_id
    FROM albums AS a LEFT JOIN tracks AS t USING (album_id)';
$result = $conn->query($sql) // return a mysqli_result object
while($row = $result->fetch_assoc()) {
    // Your loop content
}

If you insist on using foreach loop:

$result = $conn->query($sql) // return a mysqli_result object
$rows=$result->fetch_all(MYSQLI_ASSOC); //return an array
foreach($rows as $row) {
      //content
} 

Try using ON instead of USING:

$sql = 'SELECT * FROM albums AS a LEFT JOIN tracks AS t ON a.album_id = t.album_id';

This should join the two tables correctly. If there are multiple tracks for each album you will need to either query them separately or join the tracks into a group using GROUP_CONCAT. Here would be the query to accomplish this:

$sql = 'SELECT a.*, GROUP_CONCAT(t.name) as track_name FROM albums AS a LEFT JOIN tracks AS t ON a.album_id = t.album_id GROUP BY a.album_id';

Just as a side note I HIGHLY recommend using PDO for all sql related things. Here is a link to set it up and use it for safer sql queries: https://www.w3resource.com/php/pdo/php-pdo.php

ADDED TO LOOP THROUGH TRACKS

First you would need to take the variable and explode it into an array (place inside your loop):

$tracks = explode(',',$row['track_name']);
foreach($tracks as $track_name){
   echo $track_name;
}

Now you should be able to do anything you want with these tracks. You could easily place them in a table or in a div.

Two ways in which you could approach this problem:

  1. Have 2 loops - the first looping through a simple query to the albums table (no joins), then within that loop perform a second query to the database to get all the tracks. (The downside being that you will be making more queries to the database)

  2. Alternatively, change your query so you are selecting from the tracks table and then the join is on the albums table. To have it so the album title is only printed once for each album, you would need to sort the tracks by album, and then have an if statement to check when the loop has started processing a different album.

You must change your design a little. First you get the first row get the album data and the first track

After that you grap the rest of the track and close the html tags

$sql = 'SELECT a.album_id, a.album_name, a.year_released, a.record_label
        ,a.album_cover, t.name, t.album_id
        FROM albums AS a LEFT JOIN tracks AS t USING (album_id)';
  $result = $conn->query($sql) // get a result from the mysql server
  $row = $result->fetch_assoc();
?>
 <div class="col-6">
  <img src="../images/<?= $row['album_cover']?>" alt="Card image cap"  style="width:100%;">
<!--shadow-->
  <div class="shadow-lg p-3 mb-5 bg-white rounded">
    <div class="card-body" style="padding-left:10px;">
     <h4 class="card-title"><?= $row['album_name'] ?></h4>
       <b><?= print_r($row['album_name'] . ' (' . $row['record_label'] . 
        ') (' . $row['year_released'] . ')', true); ?><br><br></b>
       <ul class="list-group list-group-flush">
         <li class="list-group-item"><?= $row['name']?></li>
         <?php
         //get the rest of teh tracks
         while($row = $result->fetch_assoc()) {?>
        <li class="list-group-item"><?= $row['name']?></li>
        <?php
         }  //end if While
        ?>
     </ul>
    </div>
 </div>
 </div>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM