if the number of the columns in the php array exceeds the closing number the array breaks

Your question is a little vague. But if I understand you correctly, you want to limit the number of sales per city to the first three columns (city1, city2, city3) for every date. While keeping all the city headers in tact.

foreach might not be the best construct to do this, but seeing as you are out of your depth as it is, I will suggest something close to what you already have.

Try replacing the second occurrence of foreach ($locations as $location) { with:

foreach ($locations as $locationIndex => $location) {
    if ($locationIndex > 2)
        break;

This assumes that $locations is a simple array with a sequential numeric index. If this is not exactly what you’re trying to do, then please elaborate so I can provide a more accurate answer.

UPDATE

See this eval for a live demo of one possible approach. I used heredoc syntax for the building the HTML because it’s a little easier to read for the purpose of this example. Here’s the code. You can set $numColumns to control the number of table columns.

<?php

// Mock function to generate some random sales data, sometimes returning nothing.
function getLocationSalesForDate(DateTime $date, string $location)
{
    // Your business logic goes here.
    // Get the date as a string using DateTime::format().
    
    // Return a random mock value for this demo. Will randomly return NULL so as to simulate
    // your table view.
    return (mt_rand(0, 3) === 1)?NULL:mt_rand(15, 70);
}

$locations = ['city 1', 'city 2', 'city 3', 'city 4', 'city 5', 'city 6'];
$numColumns = 3;

$dateStart = new DateTime;
// 'P7D' means a period ('P') of 7 ('7') days ('D') from $dateStart. Consult the documentation of DateInterval's constructor for details.
$dateEnd = (clone $dateStart)->add(new DateInterval('P7D'));

// Segment your locations to however many you want to show on a single line.
foreach (array_chunk($locations, $numColumns) as $columnHeadings)
{
    // Output table heading for this group of locations.
    $html = <<<EOT
<table>
    <thead>
        <tr>
            <th>Date</th>

EOT;

    // Write out each location as a column heading.
    foreach ($columnHeadings as $columnHeading)
        $html .= <<<EOT
            <th>$columnHeading</th>

EOT;

    $html .= <<<EOT
        </tr>
    </thead>

EOT;

    // Output sales per day for this location.
    $html .= <<<EOT
    <tbody>

EOT;

    // Loop through each day between $dateStart and $dateEnd.
    $dateIterator = clone $dateStart;
    while ($dateIterator != $dateEnd)
    {
        // Start new row, print date on first column.
        $html .= <<<EOT
        <tr>
            <td>{$dateIterator->format('Y-m-d')}</td>

EOT;

        // Loop through this segment's locations and fetch sales for this day.
        foreach ($columnHeadings as $location)
        {
            // Retrieve mock sales data for this day on this location.
            $sales = getLocationSalesForDate($dateIterator, $location);
            
            // Record sales if we have any.
            if ($sales)
                // Have sales.
                $html .= <<<EOT
            <td>$sales</td>

EOT;
                else
                    // No sales for this day.
                    $html .= <<<EOT
            <td><!-- Empty cell if no sales recorded for this location on this day. --></td>

EOT;
        }
        
        // Close sales data row.
        $html .= <<<EOT
        </tr>

EOT;

        // Advance to next day for this location.
        $dateIterator->add(new DateInterval('P1D'));
    }
    
    // Close table for this location group.
    $html .= <<<EOT
    </tbody>
</table>

EOT;

    // Output table to user.
    echo $html;
}

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top