Поток: конвертировать объект в массив для экспорта в 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 подхватит и использует класс представления автоматически, как только он появится.
Внедрение пользовательских представлений подробно объясняется в этой статье - хотя на немецком языке, хотя я полагаю, что на основе именования ваших классов это не будет проблемой;).