Ângelo Rigo
Ângelo Rigo

Reputation: 2157

PHP array group by category

I have a list of stores and they can have multiple categories.

Today i display each store multiple times, one line with only one category.

How can i group the stores, creating an array of their categories, so the store is displayed only one time and have their multiple categories ?

This is my attempt:

while ($row = $query->fetch(PDO::FETCH_ASSOC)) {

    array_push(
        $stores,
        [
            "id"=> $row["id"],
            "name"=> $row["nome"],
            "categories"=> array([
                "name"=> $row["categories"]
                //how can i have an array of categories
            ])
        ]
    );
}

This is how i display the json result:

{
    id: 74,
    name: "First Store",
    categories: [
        {
            name: "Clothes"
        }
    ]
},
{
    id: 1,
    name: "Second Store",
    categories: [
        {
            name: "Food"
        }
    ]
},
{
    id: 1,
    name: "Second Store",
    categories: [
        {
            name: "Toys"
        }
    ]
},

This is how i need to show the Json:

{
    id: 74,
    name: "First Store",
    categories: [
        {
            name: "Clothes"
        }
    ]
},
{
    id: 1,
    name: "Second Store",
    categories: [
        {
            name: "Food"
        },
        {
            name: "Toys"
        }
    ]
},

In my attempt i try inside the while to create the categories but have a php warning: end() expects parameter 1 to be array, null given

if( isset($stores) ) {
    if(  end($stores['id']) != $row["id"] )  {
            array_push($category_array, $row["categories"]);
    }
} 

Upvotes: 1

Views: 204

Answers (1)

Woodrow
Woodrow

Reputation: 2832

I believe you are looking for something like this when processing your returned MySQL rows to json_encode: https://3v4l.org/d4Wf2

This will place the stores in 1 temp $storeTracker array with the store id as the array key (this assumes store id is a constant in each record you're getting back and is always the same). From here you can then check if the array key (store id) already exists, and if so, continue to add categories to the store if the category doesn't already exist. After doing this, you can then parse to json_encode to create a valid JSON object to return. Granted there may be a more eloquent way to achieve this, but this showcases the array manipulation and whatnot to try and group data for your case.

<?php

// Data coming from MySQL Database
$rowData = [];
$rowData[] = ['id' => 74, 'name' => 'First Store', 'categories' => 'Food'];
$rowData[] = ['id' => 74, 'name' => 'First Store', 'categories' => 'DVDs'];

$rowData[] = ['id' => 1, 'name' => 'Second Store', 'categories' => 'Food'];
$rowData[] = ['id' => 1, 'name' => 'Second Store', 'categories' => 'Toys'];
$rowData[] = ['id' => 1, 'name' => 'Second Store', 'categories' => 'Toys'];
$rowData[] = ['id' => 1, 'name' => 'Second Store', 'categories' => 'Clothing'];

$rowData[] = ['id' => 3, 'name' => 'Third Store', 'categories' => 'Toys'];
$rowData[] = ['id' => 3, 'name' => 'Third Store', 'categories' => 'Clothing'];
$rowData[] = ['id' => 3, 'name' => 'Third Store', 'categories' => 'Clothing'];

/**
 * Check if store category name already added to store record
 */
function categoryExistsAlready($categories, $category) {
    foreach($categories as $key => $catArr) {
        if(strtolower($catArr['name']) === strtolower($category)) {
            return true;
        }
    }
    return false;
}

$storeTracker = [];
foreach($rowData as $key => $storeData) {

    $storeCategory = $storeData['categories'];
    $storeId = $storeData['id'];

    // If store exists, add category to categories array
    if (array_key_exists($storeId, $storeTracker)) {
        if (!categoryExistsAlready($storeTracker[$storeId]['categories'], $storeCategory)) {
            $storeTracker[$storeId]['categories'][] = ['name' => $storeCategory];
        }
        continue;
    }

    // Update store categories to be array with category
    $storeData['categories'] = [];
    $storeData['categories'][] = ['name' => $storeCategory];

    // Add store data to overall tracking array
    $storeTracker[$storeId] = $storeData;
}

// Format JSON response
$jsonReturn = '[';
$i = count($storeTracker);
foreach($storeTracker as $storeId => $storeData) {
    $i--;
    $jsonReturn .= json_encode($storeData);
    // Determine last comma separating objects
    if ($i > 0) {
        $jsonReturn .= ',';
    }
}
$jsonReturn .= ']';

echo $jsonReturn;

Will give you this valid JSON https://jsonlint.com/:

[{
    "id": 74,
    "name": "First Store",
    "categories": [{
        "name": "Food"
    }, {
        "name": "DVDs"
    }]
}, {
    "id": 1,
    "name": "Second Store",
    "categories": [{
        "name": "Food"
    }, {
        "name": "Toys"
    }, {
        "name": "Clothing"
    }]
}, {
    "id": 3,
    "name": "Third Store",
    "categories": [{
        "name": "Toys"
    }, {
        "name": "Clothing"
    }]
}]

Upvotes: 1

Related Questions