1

I have an array with following format:

Array
(
    [0] => Array
        (
            [Push to Web] => Yes
            [attribute_set] => laminate_flooring
            [category] => Accessories/Underlay
            [name] => Under Pad Feather Light Foam
            [sku] => 123-1028
            [description] => Floor Underlayment Feather Light (Vapour Barrier) 200 Sqft/Roll
            [short_description] => Floor Underlayment Feather Light (Vapour Barrier) 200 Sqft/Roll
            [image] => 123-1028.jpg
            [gallery_Image] => 9095307460638-424-424.jpg
            [price] => 0.24
            [qty_ca] => 16
            [weight] => 3
            [meta_description] => 51-1001
            [meta_title] => Under Pad Feather Light Foam
            [status] => 1
            [flooring_coverage] => 200
            [is_flooring_product] => 1
            [web_price_comparative] => 0.31
        )

    [1] => Array
        (
            [Push to Web] => Yes
            [category] => Accessories
            [name] => Vent Maple Flush 4x10
            [sku] => 089-1000
            [description] => Vent Flush Mount Maple 4 x 10
            [short_description] => Vent Flush Mount Maple 4 x 10
            [image] => 089-1000.jpg
            [price] => 17.05
            [qty_ca] => 63
            [qty_us] => 41
            [meta_description] => 10-1023
            [meta_title] => Vent Maple Flush 4x10
            [status] => 1
            [flooring_coverage] => 1
            [min_order_qty] => 400
            [web_price_comparative] => 22.16
        )
)

I have to print the data in the table so that each key of array is printed as column header and the value as column data. That means Push to Web, attribute_set etc will be header and Yes, laminate_flooring will be data respectively.

I wrote the following but its not working.

 $row = 0;
$table  = '<table border="1" id="datatable">';
foreach($data as $value){
    $table .= '<tr>';
    if ($row == 0) {
        foreach($value as $innerkey=>$innervalue){
            $table .= '<td>'.$innerkey.'</td>';
        }    
    }
    $table .= '</tr><tr>';
    foreach($value as $innerkey=>$innervalue){
        $table .= '<td>'.$innervalue.'</td>';
    }
    $table .= '</tr>';
    $row++;
}
$table .= '</table>';

 print_r($table);

The output of the table should be as follows:

enter image description here

But is is showing like this enter image description here

enter image description here

First problem is the header row is continue printing only upto avalable data in first data row. Secondly If any data cell is unavailable then it is filled by next cell data. but it is supposed to be remain bank cell. Please help me to sort out the problem. Thanks in advance

mickmackusa
  • 43,625
  • 12
  • 83
  • 136
  • Do all subarrays share the same keys that you are going to use as headers later on the table? – Chemaclass May 31 '20 at 20:13
  • The example arrays above have different keys. You may want to normalize them, ie. include empty values when exporting your source data. Otherwise it's a fair bit more complicated (you would have to decipher what the total list of keys is by aggregating keys from all array members). – Markus AO May 31 '20 at 20:43
  • All right. Then there you go. You have the answer taking normalizing the headers and filling with empty data the missing headers from other arrays :) – Chemaclass May 31 '20 at 20:52

2 Answers2

3
<?php declare(strict_types=1);

/**
 * Flatting the uniqueness of all headers, which might be different 
 * from the different arrays
 */
function uniqueHeaders(array $allArrays): array
{
    return array_unique(
        call_user_func_array('array_merge', // flatting one level all keys
            array_map(function (array $a): array {
                return array_keys($a);
            }, $allArrays)
        )
    );
}

/**
 * Normalize that all arrays contain the same headers.
 * Filling with an empty string the headers that don't exists from 
 * the others.
 */
function normalizeHeaders(array $allArrays): array
{
    $headers = uniqueHeaders($allArrays);
    foreach ($allArrays as &$array) {
        foreach ($headers as $header) {
            if (!isset($array[$header])) {
                $array[$header] = '';
            }
        }
    }
    array_map('ksort', $allArrays);

    return $allArrays;
}

/**
 * This function generates the table as HTML with all array 
 * values as they come. No special "business logic" behind.
 */
function generateTable(array $allArrays): string
{
    $headers = uniqueHeaders($allArrays);
    $table = '<table border="1" id="datatable">';
    $table .= '<tr>';
    // first the headers
    foreach ($headers as $header) {
        $table .= '<th>' . $header . '</th>';
    }
    $table .= '</tr>';
    // then the values
    foreach ($allArrays as $value) {
        $table .= '<tr>';
        foreach ($value as $innervalue) {
            $table .= '<td>' . $innervalue . '</td>';
        }
        $table .= '</tr>';
    }
    $table .= '</table>';

    return $table;
}

// Usage example using different headers from each array:
$allArrays = [
    [
        'header1' => 'value11',
        'header2' => 'value12',
        'header3' => 'value13',
        'header4' => 'value14',
        'header7' => 'value17',
    ],
    [
        'header1' => 'value21',
        'header2' => 'value22',
        'header5' => 'value25',
        'header6' => 'value26',
    ],
];

$normalized = normalizeHeaders($allArrays);
$table = generateTable($normalized);
print $table . PHP_EOL;

// Unit test:
$result = <<<HTML
<table border="1" id="datatable">
    <tr>
        <th>header1</th><th>header2</th><th>header3</th><th>header4</th><th>header5</th><th>header6</th><th>header7</th>
    </tr>
    <tr>
        <td>value11</td><td>value12</td><td>value13</td><td>value14</td><td></td><td></td><td>value17</td>
    </tr>
    <tr>
        <td>value21</td><td>value22</td><td></td><td></td><td>value25</td><td>value26</td><td></td>
    </tr>
</table>
HTML;
// Result removing all spaces per line and unifying everything in one line (as the generateTable())
$expected = implode('', array_map('trim', explode(PHP_EOL, $result)));
assert($expected === $table);


Chemaclass
  • 1,933
  • 19
  • 24
-1

This assumes that all the child arrays use the same keys, which from the picture it looks like they do.

Also I've added htmlentities just to stop any rogue html breaking the table, but you can remove it if you know it's not needed.

    $table  = '<table border="1" id="datatable"><tr>';

    // Get the headers from the first child array.
    $headers = array_keys($data[0]);
    foreach($headers as $header){
        $table .= '<th>'.htmlentities($header).'</th>';
    }

    foreach($data as $value){

        $table .= '</tr><tr>';
        foreach($value as $innerkey=>$innervalue){
            $table .= '<td>'.htmlentities($innervalue).'</td>';
        }
        $table .= '</tr>';
    }
    $table .= '</table>';
DE_
  • 113
  • 7
  • mm. No, the header rows (array keys) are not present in all the array child. I have used your code but its still the same. You may check here http://159.203.4.40/var/pos-csv/phptocsv/process_product_details.php – Muntashir Are Rahi May 31 '20 at 20:38
  • That makes things a bit harder, I'll have a play around and update my answer if I get it working. – DE_ May 31 '20 at 20:41