Skip to content
Snippets Groups Projects
Commit 4f12bff4 authored by Jean-Philippe Metivier's avatar Jean-Philippe Metivier
Browse files

Importation des données depuis un csv

parent bcd41b85
No related branches found
No related tags found
No related merge requests found
Pipeline #37986 failed
Showing
with 322 additions and 7 deletions
...@@ -47,9 +47,7 @@ ...@@ -47,9 +47,7 @@
<ul> <ul>
<li style="text-decoration: line-through">Faire les insertions par batch plutôt qu'un par un.</li> <li style="text-decoration: line-through">Faire les insertions par batch plutôt qu'un par un.</li>
<li style="text-decoration: line-through">Permettre des snapshots</li> <li style="text-decoration: line-through">Permettre des snapshots</li>
<li>Dater insertion + dater suppression</li>
<li>Gestion avec un csv</li> <li>Gestion avec un csv</li>
<li>Purge des données plus vielle qu'un seuil</li>
<li><code>try_catch</code> sur les opérations.</li> <li><code>try_catch</code> sur les opérations.</li>
<li>Interface de déclaration des ORM/Applications + formulaire </li> <li>Interface de déclaration des ORM/Applications + formulaire </li>
</ul> </ul>
......
...@@ -2,11 +2,17 @@ ...@@ -2,11 +2,17 @@
use Indicateur\Controller\IndicateurController; use Indicateur\Controller\IndicateurController;
use Indicateur\Controller\IndicateurControllerFactory; use Indicateur\Controller\IndicateurControllerFactory;
use Indicateur\Form\CsvImportation\CsvImportationForm;
use Indicateur\Form\CsvImportation\CsvImportationFormFactory;
use Indicateur\Form\CsvImportation\CsvImportationHydrator;
use Indicateur\Form\CsvImportation\CsvImportationHydratorFactory;
use Indicateur\Form\Indicateur\IndicateurForm; use Indicateur\Form\Indicateur\IndicateurForm;
use Indicateur\Form\Indicateur\IndicateurFormFactory; use Indicateur\Form\Indicateur\IndicateurFormFactory;
use Indicateur\Form\Indicateur\IndicateurHydrator; use Indicateur\Form\Indicateur\IndicateurHydrator;
use Indicateur\Form\Indicateur\IndicateurHydratorFactory; use Indicateur\Form\Indicateur\IndicateurHydratorFactory;
use Indicateur\Provider\Privilege\IndicateurPrivileges; use Indicateur\Provider\Privilege\IndicateurPrivileges;
use Indicateur\Service\Csv\CsvService;
use Indicateur\Service\Csv\CsvServiceFactory;
use Indicateur\Service\Indicateur\IndicateurService; use Indicateur\Service\Indicateur\IndicateurService;
use Indicateur\Service\Indicateur\IndicateurServiceFactory; use Indicateur\Service\Indicateur\IndicateurServiceFactory;
use Indicateur\View\Helper\DefaultItemViewHelper; use Indicateur\View\Helper\DefaultItemViewHelper;
...@@ -33,6 +39,7 @@ return [ ...@@ -33,6 +39,7 @@ return [
'action' => [ 'action' => [
'creer', 'creer',
'modifier', 'modifier',
'importer-csv',
], ],
'privileges' => [ 'privileges' => [
IndicateurPrivileges::EDITER_INDICATEUR, IndicateurPrivileges::EDITER_INDICATEUR,
...@@ -143,6 +150,17 @@ return [ ...@@ -143,6 +150,17 @@ return [
], ],
'may_terminate' => true, 'may_terminate' => true,
], ],
'importer-csv' => [
'type' => Segment::class,
'options' => [
'route' => '/importer-csv/:indicateur',
'defaults' => [
/** @see IndicateurController::importerCsvAction() */
'action' => 'importer-csv',
],
],
'may_terminate' => true,
],
'detruire' => [ 'detruire' => [
'type' => Segment::class, 'type' => Segment::class,
'options' => [ 'options' => [
...@@ -173,6 +191,7 @@ return [ ...@@ -173,6 +191,7 @@ return [
'service_manager' => [ 'service_manager' => [
'factories' => [ 'factories' => [
IndicateurService::class => IndicateurServiceFactory::class, IndicateurService::class => IndicateurServiceFactory::class,
CsvService::class => CsvServiceFactory::class,
], ],
], ],
'controllers' => [ 'controllers' => [
...@@ -183,11 +202,13 @@ return [ ...@@ -183,11 +202,13 @@ return [
'form_elements' => [ 'form_elements' => [
'factories' => [ 'factories' => [
IndicateurForm::class => IndicateurFormFactory::class, IndicateurForm::class => IndicateurFormFactory::class,
CsvImportationForm::class => CsvImportationFormFactory::class,
], ],
], ],
'hydrators' => [ 'hydrators' => [
'factories' => [ 'factories' => [
IndicateurHydrator::class => IndicateurHydratorFactory::class, IndicateurHydrator::class => IndicateurHydratorFactory::class,
CsvImportationHydrator::class => CsvImportationHydratorFactory::class,
], ],
], ],
'view_helpers' => [ 'view_helpers' => [
......
...@@ -3,6 +3,8 @@ ...@@ -3,6 +3,8 @@
namespace Indicateur\Controller; namespace Indicateur\Controller;
use DateTime; use DateTime;
use Indicateur\Form\CsvImportation\CsvImportationFormAwareTrait;
use Indicateur\Service\Csv\CsvServiceAwareTrait;
use Indicateur\Service\Snapshot\SnapshotServiceAwareTrait; use Indicateur\Service\Snapshot\SnapshotServiceAwareTrait;
use Laminas\Http\Response; use Laminas\Http\Response;
use Indicateur\Entity\Db\Indicateur; use Indicateur\Entity\Db\Indicateur;
...@@ -19,6 +21,7 @@ use Laminas\Mvc\Controller\AbstractActionController; ...@@ -19,6 +21,7 @@ use Laminas\Mvc\Controller\AbstractActionController;
use Laminas\View\Model\ViewModel; use Laminas\View\Model\ViewModel;
class IndicateurController extends AbstractActionController { class IndicateurController extends AbstractActionController {
use CsvServiceAwareTrait;
use IndicateurServiceAwareTrait; use IndicateurServiceAwareTrait;
use UserServiceAwareTrait; use UserServiceAwareTrait;
use AbonnementServiceAwareTrait; use AbonnementServiceAwareTrait;
...@@ -26,6 +29,7 @@ class IndicateurController extends AbstractActionController { ...@@ -26,6 +29,7 @@ class IndicateurController extends AbstractActionController {
use PerimetreServiceAwareTrait; use PerimetreServiceAwareTrait;
use SnapshotServiceAwareTrait; use SnapshotServiceAwareTrait;
use CsvImportationFormAwareTrait;
use IndicateurFormAwareTrait; use IndicateurFormAwareTrait;
public function indexAction() : ViewModel public function indexAction() : ViewModel
...@@ -221,12 +225,37 @@ class IndicateurController extends AbstractActionController { ...@@ -221,12 +225,37 @@ class IndicateurController extends AbstractActionController {
return $CSV; return $CSV;
} }
public function rafraichirTousAction() : void public function importerCsvAction(): ViewModel|Response
{ {
$indicateurs = $this->getIndicateurService()->getIndicateurs(); $indicateur = $this->getIndicateurService()->getRequestedIndicateur($this);
foreach ($indicateurs as $indicateur) { $form = $this->getCsvImportationForm();
$this->getIndicateurService()->refresh($indicateur); $form->setAttribute('action', $this->url()->fromRoute('indicateur/importer-csv', ['indicateur' => $indicateur->getId()], [], true));
$form->bind($indicateur);
$request = $this->getRequest();
if ($request->isPost()) {
$data = $request->getPost();
$file = $request->getFiles();
$form->setData($data);
if ($form->isValid() && $file) {
$array = $this->getCsvService()->readCsv($file['fichier']['tmp_name']);
if ($data['mode'] === 'truncate') {
$this->getIndicateurService()->truncateTable($indicateur);
}
$this->getIndicateurService()->insertData($indicateur, $array);
return $this->redirect()->toRoute('indicateur/afficher', ['indicateur' => $indicateur->getId()], [], true);
} }
} }
$vm = new ViewModel();
$vm->setTemplate('default/default-form');
$vm->setVariables([
'title' => "Insertion de donnée dans l'indicateur",
'form' => $form,
]);
return $vm;
}
} }
\ No newline at end of file
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
namespace Indicateur\Controller; namespace Indicateur\Controller;
use Indicateur\Form\CsvImportation\CsvImportationForm;
use Indicateur\Service\Csv\CsvService;
use Indicateur\Service\Snapshot\SnapshotService; use Indicateur\Service\Snapshot\SnapshotService;
use Psr\Container\ContainerExceptionInterface; use Psr\Container\ContainerExceptionInterface;
use Psr\Container\NotFoundExceptionInterface; use Psr\Container\NotFoundExceptionInterface;
...@@ -25,6 +27,7 @@ class IndicateurControllerFactory { ...@@ -25,6 +27,7 @@ class IndicateurControllerFactory {
{ {
/** /**
* @var AbonnementService $abonnementService * @var AbonnementService $abonnementService
* @var CsvService $csvService
* @var IndicateurService $indicateurService * @var IndicateurService $indicateurService
* @var MailService $mailService * @var MailService $mailService
* @var UserService $userService * @var UserService $userService
...@@ -32,6 +35,7 @@ class IndicateurControllerFactory { ...@@ -32,6 +35,7 @@ class IndicateurControllerFactory {
* @var SnapshotService $snapshotService * @var SnapshotService $snapshotService
*/ */
$abonnementService = $container->get(AbonnementService::class); $abonnementService = $container->get(AbonnementService::class);
$csvService = $container->get(CsvService::class);
$indicateurService = $container->get(IndicateurService::class); $indicateurService = $container->get(IndicateurService::class);
$mailService = $container->get(MailService::class); $mailService = $container->get(MailService::class);
$userService = $container->get(UserService::class); $userService = $container->get(UserService::class);
...@@ -43,17 +47,21 @@ class IndicateurControllerFactory { ...@@ -43,17 +47,21 @@ class IndicateurControllerFactory {
$perimetreService = $container->get($perimetreServiceKey::class); $perimetreService = $container->get($perimetreServiceKey::class);
/** /**
* @var CsvImportationForm $csvImportationForm
* @var IndicateurForm $indicateurForm * @var IndicateurForm $indicateurForm
*/ */
$csvImportationForm = $container->get('FormElementManager')->get(CsvImportationForm::class);
$indicateurForm = $container->get('FormElementManager')->get(IndicateurForm::class); $indicateurForm = $container->get('FormElementManager')->get(IndicateurForm::class);
$controller = new IndicateurController(); $controller = new IndicateurController();
$controller->setAbonnementService($abonnementService); $controller->setAbonnementService($abonnementService);
$controller->setCsvService($csvService);
$controller->setIndicateurService($indicateurService); $controller->setIndicateurService($indicateurService);
$controller->setMailService($mailService); $controller->setMailService($mailService);
$controller->setPerimetreService($perimetreService); $controller->setPerimetreService($perimetreService);
$controller->setSnapshotService($snapshotService); $controller->setSnapshotService($snapshotService);
$controller->setUserService($userService); $controller->setUserService($userService);
$controller->setCsvImportationForm($csvImportationForm);
$controller->setIndicateurForm($indicateurForm); $controller->setIndicateurForm($indicateurForm);
return $controller; return $controller;
} }
......
<?php
namespace Indicateur\Form\CsvImportation;
use Laminas\Form\Element\Button;
use Laminas\Form\Element\File;
use Laminas\Form\Element\Select;
use Laminas\Form\Form;
use Laminas\InputFilter\Factory;
class CsvImportationForm extends Form {
public function init(): void
{
//file CSV
$this->add([
'type' => File::class,
'name' => 'fichier',
'options' => [
'label' => 'Fichier CSV <span class="icon icon-asterisque" title="Champ obligatoire"></span> :',
'label_options' => [ 'disable_html_escape' => true, ],
],
]);
//mode
$this->add([
'type' => Select::class,
'name' => 'mode',
'options' => [
'label' => 'Mode <span class="icon icon-asterisque" title="Champ obligatoire"></span> :',
'label_options' => [ 'disable_html_escape' => true, ],
'value_options' => [
'concat' => "Ajout aux données existantes",
'truncate' => "Écrasement des données",
]
],
'attributes' => [
'id' => 'mode',
],
]);
//Submit
$this->add([
'type' => Button::class,
'name' => 'creer',
'options' => [
'label' => 'Traiter le ficher',
'label_options' => [ 'disable_html_escape' => true, ],
],
'attributes' => [
'type' => 'submit',
'class' => 'btn btn-primary',
],
]);
$this->setInputFilter((new Factory())->createInputFilter([
'fichier' => [ 'required' => false, ],
'mode' => ['required' => true, ],
]));
}
}
\ No newline at end of file
<?php
namespace Indicateur\Form\CsvImportation;
trait CsvImportationFormAwareTrait {
private CsvImportationForm $csvImportationForm;
public function getCsvImportationForm(): CsvImportationForm
{
return $this->csvImportationForm;
}
public function setCsvImportationForm(CsvImportationForm $csvImportationForm): void
{
$this->csvImportationForm = $csvImportationForm;
}
}
\ No newline at end of file
<?php
namespace Indicateur\Form\CsvImportation;
use Psr\Container\ContainerExceptionInterface;
use Psr\Container\ContainerInterface;
use Psr\Container\NotFoundExceptionInterface;
class CsvImportationFormFactory {
/**
* @param ContainerInterface $container
* @return CsvImportationForm
* @throws ContainerExceptionInterface
* @throws NotFoundExceptionInterface
*/
public function __invoke(ContainerInterface $container) : CsvImportationForm
{
$hydrator = $container->get('HydratorManager')->get(CsvImportationHydrator::class);
$form = new CsvImportationForm();
$form->setHydrator($hydrator);
return $form;
}
}
\ No newline at end of file
<?php
namespace Indicateur\Form\CsvImportation;
use Laminas\Hydrator\HydratorInterface;
class CsvImportationHydrator implements HydratorInterface
{
public function extract(object $object): array
{
return [];
}
public function hydrate(array $data, object $object) : object
{
return $object;
}
}
<?php
namespace Indicateur\Form\CsvImportation;
use Psr\Container\ContainerInterface;
class CsvImportationHydratorFactory
{
public function __invoke(ContainerInterface $container) : CsvImportationHydrator
{
return new CsvImportationHydrator();
}
}
<?php
namespace Indicateur\Service\Csv;
use RuntimeException;
class CsvService
{
/** retour un tableau associatif correspondant au CSV */
public function readCsv(string $filename): array
{
$csvFile = fopen($filename, "r"); // Ouvrir le fichier en mode lecture
if ($csvFile === false) {
throw new RuntimeException("Impossible de lire le fichier");
}
// la première ligne est le header
if (($header = fgetcsv($csvFile)) === false) {
throw new RuntimeException("Impossible de lire l'entête du CSV");
}
$nbColumn = count($header);
// les suivantes les données
$data = [];
while (($row = fgetcsv($csvFile)) !== false) {
$item = [];
for($position = 0 ; $position < $nbColumn ; $position++) {
$item[$header[$position]] = $row[$position];
}
$data[] = $item;
}
fclose($csvFile); // Fermer le fichier
return $data;
}
}
\ No newline at end of file
<?php
namespace Indicateur\Service\Csv;
trait CsvServiceAwareTrait
{
private CsvService $csvService;
public function getCsvService(): CsvService
{
return $this->csvService;
}
public function setCsvService(CsvService $csvService): void
{
$this->csvService = $csvService;
}
}
\ No newline at end of file
<?php
namespace Indicateur\Service\Csv;
use Psr\Container\ContainerInterface;
class CsvServiceFactory
{
public function __invoke(ContainerInterface $container): CsvService
{
$service = new CsvService();
return $service;
}
}
\ No newline at end of file
...@@ -321,6 +321,51 @@ class IndicateurService ...@@ -321,6 +321,51 @@ class IndicateurService
return $tmp; return $tmp;
} }
public function insertData(Indicateur $indicateur, array $data): void
{
$batchSize = $this->getParametreService()->getValeurForParametre(GlobalParametres::TYPE, GlobalParametres::BATCH_SIZE);
// creation de la table
$champs = array_keys($data[0]);
// insertion des donnees ///////////////////////////////////////////////////////////////////////////////////////
$nbItems = count($data);
$valueDeclaration = " (" . implode(',', $champs) . ") ";
$count = 0;
foreach ($data as $item) {
if ($count % $batchSize === 0) {
$sql = "INSERT INTO " . $indicateur->getViewId() . $valueDeclaration ."VALUES ";
} else {
$sql .= ", ";
}
$values = [];
foreach ($item as $value) {
$value = str_replace("'", "''", $value);
$values[] = "'" . $value . "'";
}
$sql .= "(" . implode(',', $values) . ")";
if ($count % $batchSize === $batchSize -1 OR $count === $nbItems - 1) {
try {
$this->getObjectManager()->getConnection()->prepare($sql);
} catch (DBA_Exception $e) {
throw new RuntimeException("Un problème est survenu lors de la préparation de la requête [" . $sql . "].", 0, $e);
}
try {
$this->getObjectManager()->getConnection()->executeQuery($sql, [], []);
} catch (DBA_Driver_Exception $e) {
throw new RuntimeException("Un problème est survenu lors de l'exécution de la requête [" . $sql . "].", 0, $e);
}
}
$count++;
}
$indicateur->setDernierRafraichissement(new DateTime());
$count = $this->getCount($indicateur);
$indicateur->setNbElements($count);
$this->update($indicateur);
}
/** RECUPERATION DONNEES ******************************************************************************************/ /** RECUPERATION DONNEES ******************************************************************************************/
...@@ -365,4 +410,5 @@ class IndicateurService ...@@ -365,4 +410,5 @@ class IndicateurService
$rawdata = $this->fetch($indicateur); $rawdata = $this->fetch($indicateur);
return count($rawdata); return count($rawdata);
} }
} }
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment