2

I have an array that outputs information from DB from a single table as follow:

Array
(
    [0] => stdClass Object
        (
            [users_info_id] => 1
            [user_id] => 374
            [user_email] => [email protected]
            [address_type] => BT
            [firstname] => Foo
            [lastname] => Faa
            [vat_number] => 
            [country_code] => US
            [address] => Jajajaja
            [city] => KOKOKOKOKOKO
            [state_code] => MD
            [zipcode] => 20745
            [phone] => 2401111111
        )
    [1] => stdClass Object
        (
            [users_info_id] => 1
            [user_id] => 374
            [user_email] => [email protected]
            [address_type] => ST
            [firstname] => Foos
            [lastname] => Faas
            [vat_number] => 
            [country_code] => US
            [address] => JSUSUSUS
            [city] => LASOSLSL
            [state_code] => DC
            [zipcode] => 1234
            [phone] => 1234567895
        )
        // ... about 500 records...
)

What I'm looking for is to re-build each block of that array so the output would be something like this:

Array
(
    [0] => stdClass Object
        (
            [users_info_id] => 1
            [user_id] => 374
            [user_email] => [email protected]
            [phone] => 3213213213
            [bt] => array (
                [firstname] => Foo
                [lastname] => Faa
                [vat_number] => 
                [country_code] => US
                [address] => Jajajaja
                [city] => KOKOKOKOKOKO
                [state_code] => MD
                [zipcode] => 20745
                [phone] => 2401111111
              )
            [st] => array (
                [firstname] => Foos
                [lastname] => Faas
                [vat_number] => 
                [country_code] => US
                [address] => JSUSUSUS
                [city] => LASOSLSL
                [state_code] => DC
                [zipcode] => 1234
                [phone] => 1234567895
              )
        )

I don't even know how to start the code to make this happen, also, if you notice, the ST and BT keys came from the key address_type which is show in the first array, ST is for "shipping address" and BT is for Billing address, some users have one shipping and one for billing, but there are user who have 3 or more address for shipping...
Any help would be greatly appreciated.

2
  • Have you considered using more than one query? Grab each unique users_info_id and store them in an array. Then loop over that array and query for the unique address types and store those outputs in that same array? Commented May 13, 2015 at 20:20
  • So if you loop over $users as $user using $user['users_info_id'] for the database query condition, you could store each row like $user[$addressTypeFromDB] = $dbRow; Commented May 13, 2015 at 20:30

1 Answer 1

1

In that situation, I would use such a loop:

$outputArray = array();

$previousUserId = -1;

// Loop through all source records.
foreach ($inputRows as $row) {

   // If the current row has a different user id thn the row before,
   // add the output row to the final output array and prepare a new output row. 
   // If the current row has the same user id as the row before, 
   // just add further address information.
   // This handles also the start situation, $previousUserId = -1.
   if ($previousUserId != $row->user_id) {
       if ($previousUserId >= 0) {
           $outputArray[] = $outputRow;
       }
       $outputRow = array();

       // Copy main attributes
       $outputRow['users_info_id'] = $row->users_info_id;
       $outputRow['user_id'] = $row->user_id;
       $outputRow['user_email'] = $row->user_email;
       $outputRow['phone'] = $row->phone;
   }

   $previousUserId = $row->user_id;

   // Create a suitable address subarray and fill it.
   if ($row->address_type == 'BT') {
       $outputRow['bt'] = array();
       $outputRow['bt']['firstname'] = $row->firstname;
       $outputRow['bt']['lastname'] = $row->lastname;
       ...
   } 
   if ($row->address_type == 'ST') {
      // dito, but for ['st']
      // ...
   }
}

It is just a structure, you would have to finish it.

The code is looping through every record of your input table, let's call it $inputRows. It is important if the user_id changes, because this will start a new output row. As long as user_id remains the same, the code just adds further address types to the current output row. So, several input rows are grouped to one output row. All the output rows are then collected in an $outputArray.

Please note:

1) the dump you show in your question shows an array containing objects. In my answer, I create an array containing arrays as output. Usually, I prefer working merely with associative arrays as they offer more freedom in choosing names. If you want to work with objects, just alter the code accordingly. ($outputObject->name = ... instead of $outputObject['name'] = ...)

2) I assume that the user_id criteria is relevant for grouping input rows to new output rows. I hope this is correct ;-D

EDIT: If there are several records for address type, one could add an additional array layer like this:

   ...
   ...
   // Create a suitable address subarray and fill it.
   if ($row->address_type == 'BT') {
       // If the array that collects several bts has not been created, create it.
       if (!isset($outputRow['bt']) {
           $outputRow['bt'] = array();
       }

       // Create an array with the bt address data
       $addressData = array();
       $addressData['firstname'] = $row->firstname;
       $addressData['lastname'] = $row->lastname;
       ...

       // Add the bt address data to the collection of bts. 
       $outputRow['bt'][] = $addressData;
   } 
   if ($row->address_type == 'ST') {
      // dito, but for ['st']
      // ...
   }

With slightly more requirements, I recommend outsourcing the part that collects address data to an own function so the whole code remains readable.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, that is my start point, is working, but, if user have more than 1 ST or BT it doesn't show it, only overwrite what is there, so I added a "counter" for each one, $cst = 0 and $cbt = 0, and inside each IF type = 'BT' or ST I added the "sum" $cst++; ... following the logic in your code if user id is the same it will add another key [0], [1]... and so on until user id is different, the "counters" gets reset to 0, but is not working, on the first loop it shows [bt]=>array ([7]...) then for the next user it works fine... kind of weird...
Sorry for the late answer... I am not sure if you need a counter (or if I understand the requirement right). Please see my suggestion in the code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.