简体   繁体   中英

Flow: Convert object to array for CSV export

I want to export my object "mitglied" to a .csv-file. My controller looks like that:

public function exportAction() {

    // find all mitglieds
    $records = $this->mitgliedRepository->findTennis();

    // Set path for export-file
    $csvPath = '/var/www/apps/flow/Packages/Application/ITOOP.Atc/Resources/Private/Export/test.csv';

    $fp = fopen($csvPath, 'w');

    foreach ($records as $lines) {
        fputcsv($fp, $lines);
    }

    fclose($fp);
}

When I call the exportAction, I get a an error:

#1: Warning: fputcsv() expects parameter 2 to be array, object given in /var/www/apps/flow/Data/Temporary/Development/Cache/Code/Flow_Object_Classes/itoop_atc_Controller_MitgliedController.php line 494

line 494 is...

fputcsv($fp, $lines);

...so I think I have to convert the object "mitglied" to an array.

My the public function findTennis in my mitgliedRepository looks like that:

public function findTennis() {
    $query = $this->createQuery();
    $result = $query->matching($query->equals('abteilung', 'Tennis'))
                    ->setOrderings(array('name' => \TYPO3\Flow\Persistence\QueryInterface::ORDER_ASCENDING))
                    ->execute();

    return $result;
}

I tried to set toArray(); in the repository like the that:

public function findTennis() {
    $query = $this->createQuery();
    $result = $query->matching($query->equals('abteilung', 'Tennis'))
                    ->setOrderings(array('name' => \TYPO3\Flow\Persistence\QueryInterface::ORDER_ASCENDING))
                    ->execute()
                    ->toArray;
    return $result;
}

But then I get the following error:

#1: Notice: Undefined property: TYPO3\\Flow\\Persistence\\Doctrine\\QueryResult::$toArray in /var/www/apps/flow/Data/Temporary/Development/Cache/Code/Flow_Object_Classes/itoop_atc_Domain_Repository_MitgliedRepository.php line 105

line 105 of course is

 ->toArray;

Does anybody know, how to convert an object to an array in flow?

With the following example the export works, so I think the (formatting of the) repository query is the problem.

public function exportAction() {
    // Set path for export-file
     $csvPath = '/var/www/apps/flow/Packages/Application/ITOOP.Atc/Resources/Private/Export/test.csv';

 $test = array (
     array('xxx', 'bbb', 'ccc', 'dddd'),
     array('123', '456', '789'),
     array('aaa', 'bbb')
 );


 $fp = fopen($csvPath, 'w');

 foreach ($test as $lines) {
     fputcsv($fp, $lines);
 }

 fclose($fp);

}

Please point me to the right direction. Thank you!

The error messages explained

#1: Warning: fputcsv() expects parameter 2 to be array, object given in /var/www/apps/flow/Data/Temporary/Development/Cache/Code/Flow_Object_Classes/itoop_atc_Controller_MitgliedController.php line 494

fputcsv expects it's 2nd parameter to be an array. That array will be written as a CSV line into single file, with each array element as column. When iterating over your $records variable, you get instances of your domain object class (so probably sth. like ITOOP\\Atc\\Domain\\Model\\Mitglied ). That's undefined behaviour, thus the warning.

#1: Notice: Undefined property: TYPO3\\Flow\\Persistence\\Doctrine\\QueryResult::$toArray in /var/www/apps/flow/Data/Temporary/Development/Cache/Code/Flow_Object_Classes/itoop_atc_Domain_Repository_MitgliedRepository.php line 105

toArray is a function that is offered by Doctrine QueryResult class. Typically, Doctrine queries do not fetch all objects returned by the query, but return an iterator that fetches and maps entities on-demand. The toArray method fetches all records at once and returns an array instead of the iterator. Your error occurs, because you try to access toArray as a property, and not calling it as a method . The following code would be correct:

$result = $query->matching($query->equals('abteilung', 'Tennis'))
                ->setOrderings(array('name' => \TYPO3\Flow\Persistence\QueryInterface::ORDER_ASCENDING))
                ->execute()
                ->toArray(); // <- Mind the brackets!

However, this will not help you anything, because in your controller, you will still be iterating over a list of domain entities ( foreach does not care if its iterating over an iterator or an array; that's actually the point of iterators in PHP).

Quick&Dirty solution

Convert your domain entities by hand in your controller. Only you can know how your CSV export should look like , so this cannot be automated. I'm thinking something like this:

foreach ($records as $record) {
    $csvLine = [
        $record->getFirstProperty(),
        $record->getSecondProperty(),
        // and so on...
    ];
    fputcsv($fp, $csvLine);
}

Better solution

Rendering CSV data is not a concern that should be addressed in the controller . Basically, it should go into a view. You can implement a custom view class for handling the CSV output.

For that, you need to implement the \\TYPO3\\Flow\\Mvc\\View\\ViewInterface . The easiest way to do this is to subclass \\TYPO3\\Flow\\Mvc\\View\\AbstractView . Name your view class <PackageNamespace>\\View\\<Controller>\\Action<Format> (so sth. like ITOOP\\Atc\\View\\Mitglied\\ExportCsv . Implement your CSV export logic in the view's render() method. Flow will pick up and use the view class automatically as soon as it's present.

Implementing custom views is explained in depth in this article -- it's in German though, although based on your class naming I suspect that won't be a problem ;).

I solved the problem with arbitrary DQL. As I mentioned I think the problem was that I didn't got an array as result by the query. But with the following query in my repository I do:

/**
* @Flow\Inject
* @var \Doctrine\Common\Persistence\ObjectManager
* inject Doctrine's EntityManager to execute arbitrary DQL
*/
protected $entityManager;    

/**
* find mitglieder with Abteilung Tennis und return an array
*/
public function exportTennis() {
    $query = $this->entityManager->createQuery("SELECT mitglied FROM \itoop\atc\Domain\Model\Mitglied mitglied WHERE mitglied.abteilung = 'Tennis'");
    return $query->getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);
}

The important part I think is getResult(\\Doctrine\\ORM\\Query::HYDRATE_ARRAY);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM