5

I want to export an array of objects in CSV :

array(10) {
  [0]=>
  object(Produit)#228 (36) {
    ["id_produit":protected]=> string(4) "9999"
    ["reference":protected]=> string(9) "reference1"
}
  [1]=>
  object(Produit)#228 (36) {
    ["id_produit":protected]=> string(4) "8888"
    ["reference":protected]=> string(9) "reference2"
}
}

IN something like :

id_produit | reference | ...
9999 | reference1 | ...
8888 | reference2 | ...

The first row : list of attribut / column

The other row : value of the attribut of the Object

True Example of array with object : http://pastebin.com/8Eyf46pb

I tried this : Convert array into csv but it doesn't work for me.

Is it possible to do this (and how ?) or I have to write each attribute in a loop ?

Community
  • 1
  • 1
Snow
  • 272
  • 1
  • 5
  • 18

2 Answers2

7

It would be pretty easy if all your properties are public:

// Test class
class Produit
{
    public $id_produit;
    public $reference;

    // Test data
    public function  __construct()
    {
        $this->id_produit = rand(1, 255);
        $this->reference = rand(1, 255);
    }
}

// Test data array
$array = array(new Produit(), new Produit());

// Notice, you can only use a single character as a delimiter
$delimiter = '|';

if (count($array) > 0) {
    // prepare the file
    $fp = fopen('test/file.csv', 'w');

    // Save header
    $header = array_keys((array)$array[0]);
    fputcsv($fp, $header, $delimiter);

    // Save data
    foreach ($array as $element) {
        fputcsv($fp, (array)$element, $delimiter);
    }
}

But as I can see, your properties are protected. Which means we can't access properties outside the object as well as loop through them or use (array) typecasting. So in this case you must make some changes ot the object:

// Test class
class Produit
{
    // ...

    public function getProperties()
    {
        return array('id_produit', 'reference');
    }

    public function toArray()
    {
        $result = array();

        foreach ($this->getProperties() as $property) {
            $result[$property] = $this->$property;
        }

        return $result;
    }
}

And then instead of typecasting you can use new method toArray like this:

// Save data
foreach ($array as $element) {
    fputcsv($fp, $element->toArray(), $delimiter);
}

Also thanks to new mehod getProperties we can change header getting:

// Save header
fputcsv($fp, $array[0]->getProperties(), $delimiter);
Randell
  • 6,112
  • 6
  • 45
  • 70
ozahorulia
  • 9,798
  • 8
  • 48
  • 72
  • Thank you, I tested each of your example and I have the same result, is it normal ? (even if my propertie are protected) – Snow Feb 11 '14 at 08:25
1

I've now tested the below code and it does seem to work. Reflection was the answer.

I tried to get it working on phpfiddle hence the php://temp but it didn't work unfortunately

<?php
class Produit
{
    public $id_produit;
    public $reference;

    // Test data
    public function  __construct()
    {
        $this->id_produit = rand(1, 255);
        $this->reference = rand(1, 255);
    }
}

$array = array(new Produit(), new Produit());


$delimiter='|';
$fp=fopen('php://temp', 'w'); //replace this bit with a file name
$header=false;
foreach($array as $Produit){
    $Reflection = new ReflectionClass($Produit);
    $properties = $Reflection->getProperties();
    $row=array();
    foreach($properties as $prop){
        $row[$prop->getName()] = $prop->getValue($Produit);
    }
    if(!$header){
        fputcsv($fp, array_keys($row), $delimiter);
        $header=true;
    }
    fputcsv($fp, $row, $delimiter);
}

//now show what has been written, you will want to remove this section
fseek($fp, 0);
fpassthru($fp);
//ends

fclose($fp);
edmondscommerce
  • 2,001
  • 12
  • 21