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

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