vendor/w-vision/data-definitions/src/DataDefinitionsBundle/Exporter/Exporter.php line 322

Open in your IDE?
  1. <?php
  2. /**
  3.  * Data Definitions.
  4.  *
  5.  * LICENSE
  6.  *
  7.  * This source file is subject to the GNU General Public License version 3 (GPLv3)
  8.  * For the full copyright and license information, please view the LICENSE.md and gpl-3.0.txt
  9.  * files that are distributed with this source code.
  10.  *
  11.  * @copyright  Copyright (c) 2016-2019 w-vision AG (https://www.w-vision.ch)
  12.  * @license    https://github.com/w-vision/DataDefinitions/blob/master/gpl-3.0.txt GNU General Public License version 3 (GPLv3)
  13.  */
  14. declare(strict_types=1);
  15. namespace Wvision\Bundle\DataDefinitionsBundle\Exporter;
  16. use CoreShop\Component\Pimcore\DataObject\UnpublishedHelper;
  17. use CoreShop\Component\Registry\ServiceRegistryInterface;
  18. use Exception;
  19. use InvalidArgumentException;
  20. use Pimcore;
  21. use Pimcore\Model\DataObject\Concrete;
  22. use Psr\Log\LoggerInterface;
  23. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  24. use Wvision\Bundle\DataDefinitionsBundle\Context\ContextFactoryInterface;
  25. use Wvision\Bundle\DataDefinitionsBundle\Context\FetcherContextInterface;
  26. use Wvision\Bundle\DataDefinitionsBundle\Event\ExportDefinitionEvent;
  27. use Wvision\Bundle\DataDefinitionsBundle\Exception\UnexpectedValueException;
  28. use Wvision\Bundle\DataDefinitionsBundle\Fetcher\FetcherInterface;
  29. use Wvision\Bundle\DataDefinitionsBundle\Getter\DynamicColumnGetterInterface;
  30. use Wvision\Bundle\DataDefinitionsBundle\Getter\GetterInterface;
  31. use Wvision\Bundle\DataDefinitionsBundle\Interpreter\InterpreterInterface;
  32. use Wvision\Bundle\DataDefinitionsBundle\Model\ExportDefinitionInterface;
  33. use Wvision\Bundle\DataDefinitionsBundle\Model\ExportMapping;
  34. use Wvision\Bundle\DataDefinitionsBundle\Provider\ExportProviderInterface;
  35. use Wvision\Bundle\DataDefinitionsBundle\Runner\ExportRunnerInterface;
  36. use function is_array;
  37. final class Exporter implements ExporterInterface
  38. {
  39.     private bool $shouldStop false;
  40.     private array $exceptions = [];
  41.     public function __construct(
  42.         private ServiceRegistryInterface $fetcherRegistry,
  43.         private ServiceRegistryInterface $runnerRegistry,
  44.         private ServiceRegistryInterface $interpreterRegistry,
  45.         private ServiceRegistryInterface $getterRegistry,
  46.         private ServiceRegistryInterface $exportProviderRegistry,
  47.         private ContextFactoryInterface $contextFactory,
  48.         private EventDispatcherInterface $eventDispatcher,
  49.         private LoggerInterface $logger
  50.     ) {
  51.     }
  52.     public function doExport(ExportDefinitionInterface $definition, array $params)
  53.     {
  54.         $fetcherContext $this->contextFactory->createFetcherContext($definition$paramsis_array($definition->getFetcherConfig()) ? $definition->getFetcherConfig() : []);
  55.         $fetcher $this->getFetcher($definition);
  56.         $provider $this->getProvider($definition);
  57.         $total $fetcher->count($fetcherContext);
  58.         $this->eventDispatcher->dispatch(
  59.             new ExportDefinitionEvent($definition$total$params),
  60.             'data_definitions.export.total'
  61.         );
  62.         $this->runExport($definition$params$total$fetcherContext$fetcher$provider);
  63.         $this->eventDispatcher->dispatch(
  64.             new ExportDefinitionEvent($definitionnull$params),
  65.             'data_definitions.export.finished'
  66.         );
  67.     }
  68.     private function getFetcher(ExportDefinitionInterface $definition): FetcherInterface
  69.     {
  70.         if (!$this->fetcherRegistry->has($definition->getFetcher())) {
  71.             throw new InvalidArgumentException(
  72.                 sprintf(
  73.                     'Export Definition %s has no valid fetcher configured',
  74.                     $definition->getName()
  75.                 )
  76.             );
  77.         }
  78.         /** @var FetcherInterface $fetcher */
  79.         $fetcher $this->fetcherRegistry->get($definition->getFetcher());
  80.         return $fetcher;
  81.     }
  82.     private function getProvider(ExportDefinitionInterface $definition): ExportProviderInterface
  83.     {
  84.         if (!$this->exportProviderRegistry->has($definition->getProvider())) {
  85.             throw new InvalidArgumentException(
  86.                 sprintf(
  87.                     'Definition %s has no valid export provider configured',
  88.                     $definition->getName()
  89.                 )
  90.             );
  91.         }
  92.         return $this->exportProviderRegistry->get($definition->getProvider());
  93.     }
  94.     private function runExport(
  95.         ExportDefinitionInterface $definition,
  96.         $params,
  97.         int $total,
  98.         FetcherContextInterface $fetcherContext,
  99.         FetcherInterface $fetcher,
  100.         ExportProviderInterface $provider
  101.     ) {
  102.         UnpublishedHelper::hideUnpublished(
  103.             function () use ($definition$params$total$fetcher$provider$fetcherContext) {
  104.                 $count 0;
  105.                 $perLoop 50;
  106.                 $perRun ceil($total $perLoop);
  107.                 for ($i 0$i $perRun$i++) {
  108.                     $objects $fetcher->fetch(
  109.                         $fetcherContext,
  110.                         $perLoop,
  111.                         $i $perLoop
  112.                     );
  113.                     foreach ($objects as $object) {
  114.                         try {
  115.                             $this->exportRow($definition$object$params$provider);
  116.                             if (($count 1) % $perLoop === 0) {
  117.                                 Pimcore::collectGarbage();
  118.                                 $this->logger->info('Clean Garbage');
  119.                                 $this->eventDispatcher->dispatch(
  120.                                     new ExportDefinitionEvent($definition'Collect Garbage'$params),
  121.                                     'data_definitions.export.status'
  122.                                 );
  123.                             }
  124.                             $count++;
  125.                         } catch (Exception $ex) {
  126.                             $this->logger->error($ex);
  127.                             $this->exceptions[] = $ex;
  128.                             $this->eventDispatcher->dispatch(
  129.                                 new ExportDefinitionEvent(
  130.                                     $definitionsprintf('Error: %s'$ex->getMessage()), $params
  131.                                 ),
  132.                                 'data_definitions.export.status'
  133.                             );
  134.                             if ($definition->getStopOnException()) {
  135.                                 throw $ex;
  136.                             }
  137.                         }
  138.                         $this->eventDispatcher->dispatch(
  139.                             new ExportDefinitionEvent($definitionnull$params),
  140.                             'data_definitions.export.progress'
  141.                         );
  142.                     }
  143.                     if ($this->shouldStop) {
  144.                         $this->eventDispatcher->dispatch(
  145.                             new ExportDefinitionEvent($definition'Process has been stopped.'$params),
  146.                             'data_definitions.export.status'
  147.                         );
  148.                         return;
  149.                     }
  150.                 }
  151.                 $provider->exportData($definition->getConfiguration(), $definition$params);
  152.             },
  153.             false === $definition->isFetchUnpublished()
  154.         );
  155.     }
  156.     private function exportRow(
  157.         ExportDefinitionInterface $definition,
  158.         Concrete $object,
  159.         $params,
  160.         ExportProviderInterface $provider
  161.     ): array {
  162.         $data = [];
  163.         $runner null;
  164.         $runnerContext $this->contextFactory->createRunnerContext($definition$paramsnullnull$object);
  165.         $this->eventDispatcher->dispatch(
  166.             new ExportDefinitionEvent($definitionsprintf('Export Object %s'$object->getId()), $params),
  167.             'data_definitions.export.status'
  168.         );
  169.         $this->eventDispatcher->dispatch(
  170.             new ExportDefinitionEvent($definition$object$params),
  171.             'data_definitions.export.object.start'
  172.         );
  173.         if ($definition->getRunner()) {
  174.             $runner $this->runnerRegistry->get($definition->getRunner());
  175.         }
  176.         if ($runner instanceof ExportRunnerInterface) {
  177.             $data $runner->exportPreRun($runnerContext);
  178.         }
  179.         $this->logger->info(sprintf('Export Object: %s'$object->getRealFullPath()));
  180.         if (is_array($definition->getMapping())) {
  181.             /**
  182.              * @var ExportMapping $mapItem
  183.              */
  184.             foreach ($definition->getMapping() as $mapItem) {
  185.                 $getter $this->fetchGetter($mapItem);
  186.                 $value $this->getObjectValue(
  187.                     $object,
  188.                     $mapItem,
  189.                     $data,
  190.                     $definition,
  191.                     $params,
  192.                     $getter
  193.                 );
  194.                 if ($getter instanceof DynamicColumnGetterInterface) {
  195.                     $data array_merge($data$value);
  196.                 } else {
  197.                     $data[$mapItem->getToColumn()] = $value;
  198.                 }
  199.             }
  200.         }
  201.         $provider->addExportData($data$definition->getConfiguration(), $definition$params);
  202.         $this->eventDispatcher->dispatch(
  203.             new ExportDefinitionEvent($definitionsprintf('Exported Object %s'$object->getFullPath()), $params),
  204.             'data_definitions.export.status'
  205.         );
  206.         $this->eventDispatcher->dispatch(
  207.             new ExportDefinitionEvent($definition$object$params),
  208.             'data_definitions.export.object.finished'
  209.         );
  210.         if ($runner instanceof ExportRunnerInterface) {
  211.             $data $runner->exportPostRun($runnerContext);
  212.         }
  213.         return $data;
  214.     }
  215.     private function getObjectValue(
  216.         Concrete $object,
  217.         ExportMapping $map,
  218.         $data,
  219.         ExportDefinitionInterface $definition,
  220.         $params,
  221.         ?GetterInterface $getter
  222.     ) {
  223.         $value null;
  224.         if (null !== $getter) {
  225.             $getterContext $this->contextFactory->createGetterContext($definition$params$object$map);
  226.             $value $getter->get($getterContext);
  227.         } else {
  228.             $getter 'get'.ucfirst($map->getFromColumn());
  229.             if (method_exists($object$getter)) {
  230.                 $value $object->$getter();
  231.             }
  232.         }
  233.         if ($map->getInterpreter()) {
  234.             $interpreter $this->interpreterRegistry->get($map->getInterpreter());
  235.             if ($interpreter instanceof InterpreterInterface) {
  236.                 try {
  237.                     $context $this->contextFactory->createInterpreterContext(
  238.                         $definition,
  239.                         $params,
  240.                         $map->getInterpreterConfig(),
  241.                         $data,
  242.                         null,
  243.                         $object,
  244.                         $value,
  245.                         $map
  246.                     );
  247.                     $value $interpreter->interpret($context);
  248.                 } catch (UnexpectedValueException $ex) {
  249.                     $this->logger->info(
  250.                         sprintf(
  251.                             'Unexpected Value from Interpreter "%s" with message "%s"',
  252.                             $map->getInterpreter(),
  253.                             $ex->getMessage()
  254.                         )
  255.                     );
  256.                 }
  257.             }
  258.         }
  259.         return $value;
  260.     }
  261.     private function fetchGetter(ExportMapping $map): ?GetterInterface
  262.     {
  263.         if ($name $map->getGetter()) {
  264.             $getter $this->getterRegistry->get($name);
  265.             if ($getter instanceof GetterInterface) {
  266.                 return $getter;
  267.             }
  268.         }
  269.         return null;
  270.     }
  271.     public function stop(): void
  272.     {
  273.         $this->shouldStop true;
  274.     }
  275. }