How to handle a bad CSV file import in Symfony/PHP
Get the solution ↓↓↓I am uploading a lot of data from a csv without problem but I would like to protect a possible user error, in the sense that it is possible that they put a bad csv in the form ...
The problem is that I truncate my table every time the form is launched ...
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();
}
}
I just want that when a bad CSV file is launched that the table is not Truncate
Answer
Solution:
You can sanitize and validate data before insert into the database. You can attempt this many ways. First I would use Symfony file validator to make sure to check valid file has been uploaded.
To validate each row you can use custom callback validator or raw values of the array Validate Raw Data
//call the validator in the repository
$validator = Validation::createValidator();
// sample input
$input = [
'field_1' => 'hello',
'field_2' => '[email protected]',
'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;
}
}
Answer
Solution:
Thanks to all of you, I'm stupid, I just put a "try catch" which returns something else if an error occurs in the importMyData function, then I check in my Controller if this value is returned ... If so, I redirect etc.
Share solution ↓
Additional Information:
Link To Answer People are also looking for solutions of the problem: too few arguments to function laravel
Didn't find the answer?
Our community is visited by hundreds of web development professionals every day. Ask your question and get a quick answer for free.
Similar questions
Find the answer in similar questions on our website.
Write quick answer
Do you know the answer to this question? Write a quick response to it. With your help, we will make our community stronger.