流程:将对象转换为数组以进行 CSV 导出
Flow: Convert object to array for CSV export
我想将我的对象 "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: 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
第 494 行是...
fputcsv($fp, $lines);
...所以我想我必须将对象 "mitglied" 转换为数组。
我的 public 函数 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: 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
第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);
}
请指出正确的方向。谢谢!
错误消息解释
#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
期望它的第二个参数是一个数组。该数组将作为 CSV 行写入单个文件,每个数组元素作为列。当迭代你的 $records
变量时,你会得到你的领域对象 class 的实例(所以可能像 ITOOP\Atc\Domain\Model\Mitglied
一样)。这是未定义的行为,因此是警告。
#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
是 Doctrine QueryResult
class 提供的一个函数。通常,Doctrine 查询不会获取所有由查询 return 编辑的对象,而是 return 一个 iterator 按需获取和映射实体。 toArray
方法一次获取所有记录并且 return 是一个 数组 而不是迭代器。出现错误是因为您尝试将 toArray
作为 属性 访问,而不是将其作为方法 调用。以下代码是正确的:
$result = $query->matching($query->equals('abteilung', 'Tennis'))
->setOrderings(array('name' => \TYPO3\Flow\Persistence\QueryInterface::ORDER_ASCENDING))
->execute()
->toArray(); // <- Mind the brackets!
但是,这对您没有任何帮助,因为在您的控制器中,您仍将遍历域实体列表(foreach
不关心它是遍历迭代器还是数组;那是实际上是 PHP).
中的迭代器点
Quick&Dirty 解决方案
在控制器中手动转换域实体。 只有您可以知道 CSV 导出应该是什么样子,所以这不能自动化。我在想这样的事情:
foreach ($records as $record) {
$csvLine = [
$record->getFirstProperty(),
$record->getSecondProperty(),
// and so on...
];
fputcsv($fp, $csvLine);
}
更好的解决方案
渲染 CSV 数据不应该在控制器中解决。基本上,它应该进入一个视图。您可以实施自定义视图 class 来处理 CSV 输出。
为此,您需要实施 \TYPO3\Flow\Mvc\View\ViewInterface
。最简单的方法是subclass \TYPO3\Flow\Mvc\View\AbstractView
。将您的视图命名为 class <PackageNamespace>\View\<Controller>\Action<Format>
(所以类似 ITOOP\Atc\View\Mitglied\ExportCsv
。在视图的 render()
方法中实现您的 CSV 导出逻辑。Flow 将选择并使用视图 class 一出现就自动。
自定义视图的实现在 this article 中有深入的解释——尽管它是德语的,但根据您的 class 命名我怀疑这不会成为问题 ;)。
我用任意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);
我想将我的对象 "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: 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
第 494 行是...
fputcsv($fp, $lines);
...所以我想我必须将对象 "mitglied" 转换为数组。
我的 public 函数 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: 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
第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);
}
请指出正确的方向。谢谢!
错误消息解释
#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
期望它的第二个参数是一个数组。该数组将作为 CSV 行写入单个文件,每个数组元素作为列。当迭代你的 $records
变量时,你会得到你的领域对象 class 的实例(所以可能像 ITOOP\Atc\Domain\Model\Mitglied
一样)。这是未定义的行为,因此是警告。
#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
是 Doctrine QueryResult
class 提供的一个函数。通常,Doctrine 查询不会获取所有由查询 return 编辑的对象,而是 return 一个 iterator 按需获取和映射实体。 toArray
方法一次获取所有记录并且 return 是一个 数组 而不是迭代器。出现错误是因为您尝试将 toArray
作为 属性 访问,而不是将其作为方法 调用。以下代码是正确的:
$result = $query->matching($query->equals('abteilung', 'Tennis'))
->setOrderings(array('name' => \TYPO3\Flow\Persistence\QueryInterface::ORDER_ASCENDING))
->execute()
->toArray(); // <- Mind the brackets!
但是,这对您没有任何帮助,因为在您的控制器中,您仍将遍历域实体列表(foreach
不关心它是遍历迭代器还是数组;那是实际上是 PHP).
Quick&Dirty 解决方案
在控制器中手动转换域实体。 只有您可以知道 CSV 导出应该是什么样子,所以这不能自动化。我在想这样的事情:
foreach ($records as $record) {
$csvLine = [
$record->getFirstProperty(),
$record->getSecondProperty(),
// and so on...
];
fputcsv($fp, $csvLine);
}
更好的解决方案
渲染 CSV 数据不应该在控制器中解决。基本上,它应该进入一个视图。您可以实施自定义视图 class 来处理 CSV 输出。
为此,您需要实施 \TYPO3\Flow\Mvc\View\ViewInterface
。最简单的方法是subclass \TYPO3\Flow\Mvc\View\AbstractView
。将您的视图命名为 class <PackageNamespace>\View\<Controller>\Action<Format>
(所以类似 ITOOP\Atc\View\Mitglied\ExportCsv
。在视图的 render()
方法中实现您的 CSV 导出逻辑。Flow 将选择并使用视图 class 一出现就自动。
自定义视图的实现在 this article 中有深入的解释——尽管它是德语的,但根据您的 class 命名我怀疑这不会成为问题 ;)。
我用任意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);