diff --git a/src/Bundle/ChillPersonBundle/Command/ImportSocialWorkMetadata.php b/src/Bundle/ChillPersonBundle/Command/ImportSocialWorkMetadata.php new file mode 100644 index 000000000..e42f0ef26 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Command/ImportSocialWorkMetadata.php @@ -0,0 +1,63 @@ +importer = $socialWorkMetadata; + } + + protected function configure() + { + $this + ->setName('chill:person:import-socialwork') + ->addOption('filepath', 'f', InputOption::VALUE_REQUIRED, 'The file to import.') + ->addOption('language', 'l', InputOption::VALUE_OPTIONAL, 'The default language'); + } + + protected function execute(InputInterface $input, OutputInterface $output) + { + $filepath = $input->getOption('filepath'); + + try { + $csv = Reader::createFromPath($filepath); + } catch (Throwable $e) { + throw new Exception('Error while loading CSV.',0, $e); + } + + $csv->setDelimiter(';'); + + return true === $this->importer->import($csv) ? + 0: + 1; + } +} diff --git a/src/Bundle/ChillPersonBundle/Service/Import/ChillImporter.php b/src/Bundle/ChillPersonBundle/Service/Import/ChillImporter.php new file mode 100644 index 000000000..4360a7cfa --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Service/Import/ChillImporter.php @@ -0,0 +1,10 @@ +socialIssueRepository = $socialIssueRepository; + $this->socialActionRepository = $socialActionRepository; + $this->goalRepository = $goalRepository; + $this->resultRepository = $resultRepository; + $this->evaluationRepository = $evaluationRepository; + $this->entityManager = $entityManager; + } + + public function import(iterable $dataset): bool + { + foreach ($dataset as $row) { + $this->import1( + array_map( + static fn (string $column): ?string => '' === $column ? null : $column, + array_map('trim', $row) + ) + ); + } + + return true; + } + + private function import1(array $row): void + { + // Structure: + // Index 0: SocialIssue + // Index 1: SocialIssue.children + // Index 2: SocialAction + // Index 3: SocialAction.children + // Index 4: Goal + // Index 5: Result + // Index 6: Evaluation + + $socialIssue = $this->handleSocialIssue($row[0], $row[1]); + + $socialAction = $this->handleSocialAction($row[2], $row[3], $socialIssue); + + $goal = $this->handleGoal($row[4], $socialAction); + + $result = $this->handleResult($row[5], $socialAction, $goal); + + $eval = $this->handleEvaluation($row[6], $socialAction); + + $this->entityManager->flush(); + } + + private function handleSocialIssue(?string $socialIssueTitle = null, ?string $socialIssueChildrenTitle = null): SocialIssue + { + if (null !== $socialIssueChildrenTitle) { + /** @var SocialIssue $socialIssueChildren */ + $socialIssueChildren = $this->getOrCreateEntity($this->socialIssueRepository, 'title', ['fr' => $socialIssueChildrenTitle]); + $socialIssueChildren->setTitle(['fr' => $socialIssueChildrenTitle]); + + $this->entityManager->persist($socialIssueChildren); + } + + /** @var SocialIssue $socialIssue */ + $socialIssue = $this->getOrCreateEntity($this->socialIssueRepository, 'title', ['fr' => $socialIssueTitle]); + $socialIssue->setTitle(['fr' => $socialIssueTitle]); + + if (null !== $socialIssueChildrenTitle) { + $socialIssue->addChild($socialIssueChildren); + } + + $this->entityManager->persist($socialIssue); + + return null === $socialIssueChildrenTitle ? $socialIssue : $socialIssueChildren; + } + + private function handleSocialAction(?string $socialActionTitle, ?string $socialActionChildrenTitle, SocialIssue $socialIssue): SocialAction + { + if (null !== $socialActionChildrenTitle) { + /** @var SocialAction $socialActionChildren */ + $socialActionChildren = $this->getOrCreateEntity($this->socialActionRepository, 'title', ['fr' => $socialActionChildrenTitle]); + $socialActionChildren->setTitle(['fr' => $socialActionChildrenTitle]); + + $this->entityManager->persist($socialActionChildren); + } + + /** @var SocialIssue $socialIssue */ + $socialAction = $this->getOrCreateEntity($this->socialActionRepository, 'title', ['fr' => $socialActionTitle]); + $socialAction->setTitle(['fr' => $socialActionTitle]); + + if (null !== $socialActionChildrenTitle) { + $socialActionChildren->setIssue($socialIssue); + $this->entityManager->persist($socialActionChildren); + + $socialAction->addChild($socialActionChildren); + } else { + $socialAction->setIssue($socialIssue); + } + + $this->entityManager->persist($socialAction); + + return null === $socialActionChildrenTitle ? $socialAction : $socialActionChildren; + } + + private function handleGoal(?string $goalTitle = null, ?SocialAction $socialAction = null): ?Goal + { + if (null === $goalTitle) { + return null; + } + + /** @var Goal $goal */ + $goal = $this->getOrCreateEntity($this->goalRepository, 'title', ['fr' => $goalTitle]); + $goal->setTitle(['fr' => $goalTitle]); + + if (null !== $socialAction) { + $goal->addSocialAction($socialAction); + } + + $this->entityManager->persist($goal); + + return $goal; + } + + private function handleResult(?string $resultTitle = null, SocialAction $socialAction, ?Goal $goal = null): ?Result + { + if (null === $resultTitle) { + return null; + } + + /** @var Result $result */ + $result = $this->getOrCreateEntity($this->resultRepository, 'title', ['fr' => $resultTitle]); + $result->setTitle(['fr' => $resultTitle]); + + if (null !== $goal) { + $result->addGoal($goal); + } + + // Why this cannot be found from the Goal entity? + $result->addSocialAction($socialAction); + + $this->entityManager->persist($result); + + return $result; + } + + private function handleEvaluation(?string $evaluationTitle, SocialAction $socialAction): ?Evaluation + { + if (null === $evaluationTitle) { + return null; + } + + /** @var Evaluation $eval */ + $eval = $this->getOrCreateEntity($this->evaluationRepository, 'title', ['fr' => $evaluationTitle]); + $eval->setTitle(['fr' => $evaluationTitle]); + $eval->setSocialAction($socialAction); + + $this->entityManager->persist($eval); + + return $eval; + } + + private function findByJson(ObjectRepository $repository, string $field, array $jsonCriterias): array + { + $qb = $this + ->entityManager + ->createQueryBuilder() + ->select('s') + ->from($repository->getClassName(), 's'); + + $expr = $qb->expr(); + + $temporaryJsonCriterias = $jsonParameters = []; + + foreach ($jsonCriterias as $key => $value) { + $temporaryJsonCriterias[] = [$field, $key, $value, sprintf(':placeholder_%s_%s', $field, $key)]; + } + + $jsonParameters = array_reduce( + $temporaryJsonCriterias, + static function (array $carry, array $row): array + { + [,, $value, $placeholder] = $row; + + return array_merge( + $carry, + [ + $placeholder => sprintf('"%s"', $value), + ] + ); + }, + [] + ); + + $jsonPredicates = array_map( + static function (array $row) use ($expr): Comparison + { + [$field, $key,, $placeholder] = $row; + + $left = sprintf( + "GET_JSON_FIELD_BY_KEY(s.%s, '%s')", + $field, + $key + ); + + return $expr + ->eq( + $left, + $placeholder + ); + }, + $temporaryJsonCriterias + ); + + $query = $qb + ->select('s') + ->where(...$jsonPredicates) + ->setParameters($jsonParameters) + ->getQuery(); + + return $query->getResult(); + } + + private function getOrCreateEntity(ObjectRepository $repository, string $field, array $jsonCriterias = []) + { + $results = $this + ->findByJson( + $repository, + $field, + $jsonCriterias + ); + + switch (true) { + case count($results) === 0: + $entity = $repository->getClassName(); + $entity = new $entity(); + break; + case count($results) === 1; + $entity = current($results); + break; + case count($results) > 1; + throw new Exception( + sprintf( + 'More than one entity(%s) found.', + $repository->getClassName() + ) + ); + } + + return $entity; + } + + +} diff --git a/src/Bundle/ChillPersonBundle/Service/Import/SocialWorkMetadataInterface.php b/src/Bundle/ChillPersonBundle/Service/Import/SocialWorkMetadataInterface.php new file mode 100644 index 000000000..015ef7485 --- /dev/null +++ b/src/Bundle/ChillPersonBundle/Service/Import/SocialWorkMetadataInterface.php @@ -0,0 +1,9 @@ +