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

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\Event\ExportDefinitionEvent;
  25. use Wvision\Bundle\DataDefinitionsBundle\Exception\DoNotSetException;
  26. use Wvision\Bundle\DataDefinitionsBundle\Exception\UnexpectedValueException;
  27. use Wvision\Bundle\DataDefinitionsBundle\Fetcher\FetcherInterface;
  28. use Wvision\Bundle\DataDefinitionsBundle\Getter\DynamicColumnGetterInterface;
  29. use Wvision\Bundle\DataDefinitionsBundle\Getter\GetterInterface;
  30. use Wvision\Bundle\DataDefinitionsBundle\Interpreter\InterpreterInterface;
  31. use Wvision\Bundle\DataDefinitionsBundle\Model\ExportDefinitionInterface;
  32. use Wvision\Bundle\DataDefinitionsBundle\Model\ExportMapping;
  33. use Wvision\Bundle\DataDefinitionsBundle\Provider\ExportProviderInterface;
  34. use Wvision\Bundle\DataDefinitionsBundle\Runner\ExportRunnerInterface;
  35. use function is_array;
  36. final class Exporter implements ExporterInterface
  37. {
  38.     private ServiceRegistryInterface$fetcherRegistry;
  39.     private ServiceRegistryInterface$runnerRegistry;
  40.     private ServiceRegistryInterface$interpreterRegistry;
  41.     private ServiceRegistryInterface$getterRegistry;
  42.     private ServiceRegistryInterface$exportProviderRegistry;
  43.     private EventDispatcherInterface$eventDispatcher;
  44.     private LoggerInterface$logger;
  45.     private array $exceptions = [];
  46.     private bool $shouldStop false;
  47.     public function __construct(
  48.         ServiceRegistryInterface $fetcherRegistry,
  49.         ServiceRegistryInterface $runnerRegistry,
  50.         ServiceRegistryInterface $interpreterRegistry,
  51.         ServiceRegistryInterface $getterRegistry,
  52.         ServiceRegistryInterface $exportProviderRegistry,
  53.         EventDispatcherInterface $eventDispatcher,
  54.         LoggerInterface $logger
  55.     ) {
  56.         $this->fetcherRegistry $fetcherRegistry;
  57.         $this->runnerRegistry $runnerRegistry;
  58.         $this->interpreterRegistry $interpreterRegistry;
  59.         $this->getterRegistry $getterRegistry;
  60.         $this->exportProviderRegistry $exportProviderRegistry;
  61.         $this->eventDispatcher $eventDispatcher;
  62.         $this->logger $logger;
  63.     }
  64.     public function doExport(ExportDefinitionInterface $definition, array $params)
  65.     {
  66.         $fetcher $this->getFetcher($definition);
  67.         $provider $this->getProvider($definition);
  68.         $total $fetcher->count($definition$params,
  69.             is_array($definition->getFetcherConfig()) ? $definition->getFetcherConfig() : []);
  70.         $this->eventDispatcher->dispatch(
  71.             new ExportDefinitionEvent($definition$total$params),
  72.             'data_definitions.export.total'
  73.         );
  74.         $this->runExport($definition$params$total$fetcher$provider);
  75.         $this->eventDispatcher->dispatch(
  76.             new ExportDefinitionEvent($definitionnull$params),
  77.             'data_definitions.export.finished'
  78.         );
  79.     }
  80.     private function getFetcher(ExportDefinitionInterface $definition): FetcherInterface
  81.     {
  82.         if (!$this->fetcherRegistry->has($definition->getFetcher())) {
  83.             throw new InvalidArgumentException(sprintf('Export Definition %s has no valid fetcher configured',
  84.                 $definition->getName()));
  85.         }
  86.         /** @var FetcherInterface $fetcher */
  87.         $fetcher $this->fetcherRegistry->get($definition->getFetcher());
  88.         return $fetcher;
  89.     }
  90.     private function getProvider(ExportDefinitionInterface $definition): ExportProviderInterface
  91.     {
  92.         if (!$this->exportProviderRegistry->has($definition->getProvider())) {
  93.             throw new InvalidArgumentException(sprintf('Definition %s has no valid export provider configured',
  94.                 $definition->getName()));
  95.         }
  96.         return $this->exportProviderRegistry->get($definition->getProvider());
  97.     }
  98.     private function runExport(
  99.         ExportDefinitionInterface $definition,
  100.         $params,
  101.         int $total,
  102.         FetcherInterface $fetcher,
  103.         ExportProviderInterface $provider
  104.     ) {
  105.         UnpublishedHelper::hideUnpublished(
  106.             function () use ($definition$params$total$fetcher$provider) {
  107.                 $count 0;
  108.                 $countToClean 1000;
  109.                 $perLoop 50;
  110.                 $perRun ceil($total $perLoop);
  111.                 for ($i 0$i $perRun$i++) {
  112.                     $objects $fetcher->fetch(
  113.                         $definition,
  114.                         $params,
  115.                         $perLoop,
  116.                         $i $perLoop,
  117.                         is_array($definition->getFetcherConfig()) ? $definition->getFetcherConfig() : []
  118.                     );
  119.                     foreach ($objects as $object) {
  120.                         try {
  121.                             $this->exportRow($definition$object$params$provider);
  122.                             if (($count 1) % $countToClean === 0) {
  123.                                 Pimcore::collectGarbage();
  124.                                 $this->logger->info('Clean Garbage');
  125.                                 $this->eventDispatcher->dispatch(
  126.                                     new ExportDefinitionEvent($definition'Collect Garbage'$params),
  127.                                     'data_definitions.export.status'
  128.                                 );
  129.                             }
  130.                             $count++;
  131.                         } catch (Exception $ex) {
  132.                             $this->logger->error($ex);
  133.                             $this->exceptions[] = $ex;
  134.                             $this->eventDispatcher->dispatch(
  135.                                 new ExportDefinitionEvent($definitionsprintf('Error: %s'$ex->getMessage()), $params),
  136.                                 'data_definitions.export.status'
  137.                             );
  138.                             if ($definition->getStopOnException()) {
  139.                                 throw $ex;
  140.                             }
  141.                         }
  142.                         $this->eventDispatcher->dispatch(
  143.                             new ExportDefinitionEvent($definitionnull$params),
  144.                             'data_definitions.export.progress'
  145.                         );
  146.                     }
  147.                     if ($this->shouldStop) {
  148.                         $this->eventDispatcher->dispatch(
  149.                             new ExportDefinitionEvent($definition'Process has been stopped.'$params),
  150.                             'data_definitions.export.status'
  151.                         );
  152.                         return;
  153.                     }
  154.                 }
  155.                 $provider->exportData($definition->getConfiguration(), $definition$params);
  156.             },
  157.             false === $definition->isFetchUnpublished()
  158.         );
  159.     }
  160.     private function exportRow(
  161.         ExportDefinitionInterface $definition,
  162.         Concrete $object,
  163.         $params,
  164.         ExportProviderInterface $provider
  165.     ): array {
  166.         $data = [];
  167.         $runner null;
  168.         $this->eventDispatcher->dispatch(
  169.             new ExportDefinitionEvent($definitionsprintf('Export Object %s'$object->getId()), $params),
  170.             'data_definitions.export.status'
  171.         );
  172.         $this->eventDispatcher->dispatch(
  173.             new ExportDefinitionEvent($definition$object$params),
  174.             'data_definitions.export.object.start'
  175.         );
  176.         if ($definition->getRunner()) {
  177.             $runner $this->runnerRegistry->get($definition->getRunner());
  178.         }
  179.         if ($runner instanceof ExportRunnerInterface) {
  180.             $data $runner->exportPreRun($object$data$definition$params);
  181.         }
  182.         $this->logger->info(sprintf('Export Object: %s'$object->getRealFullPath()));
  183.         if (is_array($definition->getMapping())) {
  184.             /**
  185.              * @var ExportMapping $mapItem
  186.              */
  187.             foreach ($definition->getMapping() as $mapItem) {
  188.                 $getter $this->fetchGetter($mapItem);
  189.                 $value $this->getObjectValue(
  190.                     $object,
  191.                     $mapItem,
  192.                     $data,
  193.                     $definition,
  194.                     $params,
  195.                     $getter
  196.                 );
  197.                 if ($getter instanceof DynamicColumnGetterInterface) {
  198.                     $data array_merge($data$value);
  199.                 } else {
  200.                     $data[$mapItem->getToColumn()] = $value;
  201.                 }
  202.             }
  203.         }
  204.         $provider->addExportData($data$definition->getConfiguration(), $definition$params);
  205.         $this->eventDispatcher->dispatch(
  206.             new ExportDefinitionEvent($definitionsprintf('Exported Object %s'$object->getFullPath()), $params),
  207.             'data_definitions.export.status'
  208.         );
  209.         $this->eventDispatcher->dispatch(
  210.             new ExportDefinitionEvent($definition$object$params),
  211.             'data_definitions.export.object.finished'
  212.         );
  213.         if ($runner instanceof ExportRunnerInterface) {
  214.             $data $runner->exportPostRun($object$data$definition$params);
  215.         }
  216.         return $data;
  217.     }
  218.     private function getObjectValue(
  219.         Concrete $object,
  220.         ExportMapping $map,
  221.         $data,
  222.         ExportDefinitionInterface $definition,
  223.         $params,
  224.         ?GetterInterface $getter
  225.     ) {
  226.         $value null;
  227.         if (null !== $getter) {
  228.             $value $getter->get($object$map$data);
  229.         } else {
  230.             $getter 'get' ucfirst($map->getFromColumn());
  231.             if (method_exists($object$getter)) {
  232.                 $value $object->$getter();
  233.             }
  234.         }
  235.         if ($map->getInterpreter()) {
  236.             $interpreter $this->interpreterRegistry->get($map->getInterpreter());
  237.             if ($interpreter instanceof InterpreterInterface) {
  238.                 try {
  239.                     $value $interpreter->interpret(
  240.                         $object,
  241.                         $value,
  242.                         $map,
  243.                         $data,
  244.                         $definition,
  245.                         $params,
  246.                         $map->getInterpreterConfig()
  247.                     );
  248.                 }
  249.                 catch (UnexpectedValueException $ex) {
  250.                     $this->logger->info(sprintf('Unexpected Value from Interpreter "%s" with message "%s"'$map->getInterpreter(), $ex->getMessage()));
  251.                 }
  252.             }
  253.         }
  254.         return $value;
  255.     }
  256.     private function fetchGetter(ExportMapping $map): ?GetterInterface
  257.     {
  258.         if ($name $map->getGetter()) {
  259.             $getter $this->getterRegistry->get($name);
  260.             if ($getter instanceof GetterInterface) {
  261.                 return $getter;
  262.             }
  263.         }
  264.         return null;
  265.     }
  266.     public function stop() : void
  267.     {
  268.         $this->shouldStop true;
  269.     }
  270. }