如何在 Symfony/PHP 中处理错误的 CSV 文件导入
How to handle a bad CSV file import in Symfony/PHP
我正在从 csv 上传大量数据没有问题,但是我想保护可能的用户错误,在感觉他们有可能将错误的 csv 放在表格中......
问题是每次启动表单时我都会截断 table ...
ImportController.php
$form = $this->createFormBuilder()
->add('form', FileType::class, [
'attr' => ['accept' => '.csv',
'class' => 'custom-file-input'],
'label' => 'Import'
])
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
/**
* @var UploadedFile
*/
$file = $form->get('form')->getData();
$connection = $em->getConnection();
$platform = $connection->getDatabasePlatform();
$connection->beginTransaction();
$connection->executeQuery($platform->getTruncateTableSQL('MyTable', true));
$this->getDoctrine()->getManager()->getRepository(MyTable::class)->importMyData($file);
$this->addFlash('success',"The csv has been successfully imported");
return $this->redirectToRoute('import');
}
MyTableRepository.php
public function importMyData($file)
{
$em = $this->entityManager;
if (($handle = fopen($file->getPathname(), "r")) !== false)
{
$count = 0;
$batchSize = 1000;
$data = fgetcsv($handle, 0, ",");
while (($data = fgetcsv($handle, 0, ",")) !== false)
{
$count++;
$entity = new MyTable();
// 40 entity fields...
$entity->setFieldOne($data[0]);
$entity->setFieldTwo($data[1]);
//....
$entity->setFieldForty($data[39]);
$em->persist($entity);
if (($count % $batchSize) === 0 )
{
$em->flush();
$em->clear();
}
}
fclose($handle);
$em->flush();
$em->clear();
}
}
我只想在启动错误的 CSV 文件时 table 不是 Truncate
您可以在将数据插入数据库之前清理和验证数据。您可以尝试多种方法。首先,我会使用 Symfony 文件验证器来确保检查是否已上传有效文件。
要验证每一行,您可以使用自定义回调验证器或数组的原始值
Validate Raw Data
//call the validator in the repository
$validator = Validation::createValidator();
// sample input
$input = [
'field_1' => 'hello',
'field_2' => 'test@email.tld',
'field_40' => 3
];
//define the constraints for each row
$constraint = new Assert\Collection([
// the keys correspond to the keys in the input array
'field_1' => new Assert\Collection([
'first_name' => new Assert\Length(['min' => 101]),
'last_name' => new Assert\Length(['min' => 1]),
]),
'field_2' => new Assert\Email(),
'field_40' => new Assert\Length(['min' => 102])
]);
while (($data = fgetcsv($handle, 0, ",")) !== false) {
$violations = $validator->validate($data, $constraint);
// you can skip the row or log the error
if ($violations->count() > 0) {
continue;
}
}
感谢大家,我很笨,我只是放了一个“try catch”,如果 importMyData 函数中发生错误,returns 其他东西,然后我检查我的控制器是否返回这个值...如果是这样,我重定向等
我正在从 csv 上传大量数据没有问题,但是我想保护可能的用户错误,在感觉他们有可能将错误的 csv 放在表格中......
问题是每次启动表单时我都会截断 table ...
ImportController.php
$form = $this->createFormBuilder()
->add('form', FileType::class, [
'attr' => ['accept' => '.csv',
'class' => 'custom-file-input'],
'label' => 'Import'
])
->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid())
{
/**
* @var UploadedFile
*/
$file = $form->get('form')->getData();
$connection = $em->getConnection();
$platform = $connection->getDatabasePlatform();
$connection->beginTransaction();
$connection->executeQuery($platform->getTruncateTableSQL('MyTable', true));
$this->getDoctrine()->getManager()->getRepository(MyTable::class)->importMyData($file);
$this->addFlash('success',"The csv has been successfully imported");
return $this->redirectToRoute('import');
}
MyTableRepository.php
public function importMyData($file)
{
$em = $this->entityManager;
if (($handle = fopen($file->getPathname(), "r")) !== false)
{
$count = 0;
$batchSize = 1000;
$data = fgetcsv($handle, 0, ",");
while (($data = fgetcsv($handle, 0, ",")) !== false)
{
$count++;
$entity = new MyTable();
// 40 entity fields...
$entity->setFieldOne($data[0]);
$entity->setFieldTwo($data[1]);
//....
$entity->setFieldForty($data[39]);
$em->persist($entity);
if (($count % $batchSize) === 0 )
{
$em->flush();
$em->clear();
}
}
fclose($handle);
$em->flush();
$em->clear();
}
}
我只想在启动错误的 CSV 文件时 table 不是 Truncate
您可以在将数据插入数据库之前清理和验证数据。您可以尝试多种方法。首先,我会使用 Symfony 文件验证器来确保检查是否已上传有效文件。
要验证每一行,您可以使用自定义回调验证器或数组的原始值 Validate Raw Data
//call the validator in the repository
$validator = Validation::createValidator();
// sample input
$input = [
'field_1' => 'hello',
'field_2' => 'test@email.tld',
'field_40' => 3
];
//define the constraints for each row
$constraint = new Assert\Collection([
// the keys correspond to the keys in the input array
'field_1' => new Assert\Collection([
'first_name' => new Assert\Length(['min' => 101]),
'last_name' => new Assert\Length(['min' => 1]),
]),
'field_2' => new Assert\Email(),
'field_40' => new Assert\Length(['min' => 102])
]);
while (($data = fgetcsv($handle, 0, ",")) !== false) {
$violations = $validator->validate($data, $constraint);
// you can skip the row or log the error
if ($violations->count() > 0) {
continue;
}
}
感谢大家,我很笨,我只是放了一个“try catch”,如果 importMyData 函数中发生错误,returns 其他东西,然后我检查我的控制器是否返回这个值...如果是这样,我重定向等