Поток: конвертировать объект в массив для экспорта в CSV

Я хочу экспортировать мой объект "mitglied" в.csv-файл. Мой контроллер выглядит так:

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);
}

Когда я вызываю exportAction, я получаю сообщение об ошибке:

# 1: Предупреждение: fputcsv() ожидает, что параметр 2 будет массивом, объект указан в /var/www/apps/flow/Data/Teorary/Development/Cache/Code/Flow_Object_Classes/itoop_atc_Controller_MitgliedController.php строка 494

строка 494 является...

fputcsv($fp, $lines);

... так что я думаю, что я должен преобразовать объект "Mitglied" в массив.

Моя публичная функция findTennis в моем mitgliedRepository выглядит так:

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;
}

Я пытался установить toArray(); в репозитории вроде того:

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;
}

Но тогда я получаю следующую ошибку:

# 1: Обратите внимание: неопределенное свойство: TYPO3\Flow\Persistence\Doctrine\QueryResult::$toArray в /var/www/apps/flow/Data/Teilitary/Development/Cache/Code/Flow_Object_Classes/itoop_atc_Domain_Repository_MitgliedRepository.MedphliedRepository. 105

линия 105, конечно,

 ->toArray;

Кто-нибудь знает, как преобразовать объект в массив в потоке?

В следующем примере экспорт работает, поэтому я думаю, что (форматирование) запроса к репозиторию является проблемой.

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);

}

Пожалуйста, укажите мне правильное направление. Спасибо!

2 ответа

Решение

Я решил проблему с произвольным DQL. Как я уже говорил, проблема в том, что я не получил массив в результате запроса. Но со следующим запросом в моем хранилище я делаю:

/**
* @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);
}

Важная часть, я думаю, это getResult(\Doctrine\ORM\Query::HYDRATE_ARRAY);

Сообщения об ошибках объяснены

#1: Предупреждение: fputcsv() ожидает, что параметр 2 будет массивом, объект указан в /var/www/apps/flow/Data/Teorary/Development/Cache/Code/Flow_Object_Classes/itoop_atc_Controller_MitgliedController.php строка 494

fputcsv ожидает, что его второй параметр будет массивом. Этот массив будет записан в виде CSV-строки в один файл с каждым элементом массива в виде столбца. При переборе вашего $records переменная, вы получаете экземпляры вашего класса объекта домена (так что, вероятно, что-то вроде ITOOP\Atc\Domain\Model\Mitglied). Это неопределенное поведение, следовательно, предупреждение.

#1: Обратите внимание: неопределенное свойство: TYPO3\Flow\Persistence\Doctrine\QueryResult::$toArray в /var/www/apps/flow/Data/Teilitary/Development/Cache/Code/Flow_Object_Classes/itoop_atc_Domain_Repository_MitgliedRepository.MedphliedRepository. 105

toArray это функция, которая предлагается доктриной QueryResult учебный класс. Как правило, запросы Doctrine не выбирают все объекты, возвращенные запросом, но возвращают итератор, который выбирает и отображает объекты по требованию. toArray Метод извлекает все записи сразу и возвращает массив вместо итератора. Ваша ошибка возникает, потому что вы пытаетесь получить доступ toArray как свойство, а не вызывая его как метод. Следующий код будет правильным:

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

Однако это вам ничем не поможет, потому что в вашем контроллере вы все равно будете перебирать список доменных сущностей (foreach не заботится, повторяется ли он над итератором или массивом; это на самом деле смысл итераторов в PHP).

Быстрое и грязное решение

Конвертируйте ваши доменные объекты вручную в вашем контроллере. Только вы можете знать, как должен выглядеть экспорт CSV, поэтому это невозможно автоматизировать. Я думаю что-то вроде этого:

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

Лучшее решение

Рендеринг CSV-данных не является проблемой, которая должна решаться в контроллере. В принципе, это должно идти в поле зрения. Вы можете реализовать собственный класс представления для обработки вывода CSV.

Для этого вам необходимо реализовать \TYPO3\Flow\Mvc\View\ViewInterface, Самый простой способ сделать это подкласс \TYPO3\Flow\Mvc\View\AbstractView, Назовите свой класс просмотра <PackageNamespace>\View\<Controller>\Action<Format> (так что ITOOP\Atc\View\Mitglied\ExportCsv, Реализуйте свою логику экспорта CSV в представлении render() метод. Flow подхватит и использует класс представления автоматически, как только он появится.

Внедрение пользовательских представлений подробно объясняется в этой статье - хотя на немецком языке, хотя я полагаю, что на основе именования ваших классов это не будет проблемой;).

Другие вопросы по тегам