Advertisement
Guest User

Untitled

a guest
Mar 20th, 2018
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 11.88 KB | None | 0 0
  1. <?php
  2.  
  3. declare(strict_types=1);
  4.  
  5. namespace App\Services;
  6.  
  7. use App\Services\Api\NovaPoshta;
  8. use App\Entity\City;
  9. use App\Entity\Warehouse;
  10. use App\Messages\Console\NovaPoshta\SyncConsole;
  11. use App\Messages\Logger\NovaPoshta\SyncLog;
  12. use Doctrine\ORM\EntityManagerInterface;
  13. use Psr\Log\InvalidArgumentException;
  14. use Symfony\Component\Console\Output\OutputInterface;
  15.  
  16. class Sync
  17. {
  18.     /** @var EntityManagerInterface $em */
  19.     private $em;
  20.  
  21.     /** @var NovaPoshta $api */
  22.     private $api;
  23.  
  24.     /** @var SyncLog $log */
  25.     private $log;
  26.  
  27.     /** @var float $percent */
  28.     private $percent = 0.9;
  29.  
  30.     /** @var $citiesApi array */
  31.     private $citiesApi;
  32.  
  33.     /** @var $warehousesApi array */
  34.     private $warehousesApi;
  35.  
  36.     /** @var $citiesDB array */
  37.     private $citiesDB;
  38.  
  39.     /** @var $warehousesDB array */
  40.     private $warehousesDB;
  41.  
  42.     /** @var $console SyncConsole */
  43.     private $console;
  44.  
  45.     public function __construct(EntityManagerInterface $em, NovaPoshta $api, SyncLog $logger, SyncConsole $console)
  46.     {
  47.         $this->em = $em;
  48.         $this->api = $api;
  49.         $this->log = $logger;
  50.         $this->console = $console;
  51.     }
  52.  
  53.     public function run(OutputInterface $output): void
  54.     {
  55.         $console = $this->console->init($output);
  56.         $log = $this->log;
  57.  
  58.         $console->syncCheckDifference();
  59.         try {
  60.             $this->checkDifference();
  61.  
  62.         } catch (InvalidArgumentException $e) {
  63.             $console->syncFailed();
  64.             $log->syncFailedViaDifference();
  65.             $log->syncFailed();
  66.         }
  67.  
  68.         $console->syncStart();
  69.         $log->syncStart();
  70.  
  71.         $console->syncCitiesStart();
  72.         $log->syncCitiesStart();
  73.         try {
  74.             $this->synchronizeCities();
  75.  
  76.             $console->synCitiesComplete();
  77.             $log->syncCitiesEnd();
  78.         } catch (\Exception $e) {
  79.             $log->syncCitiesFailed();
  80.             $log->syncException($e);
  81.         }
  82.  
  83.         $console->syncWarehousesStart();
  84.         $log->syncWarehousesStart();
  85.         try {
  86.             $this->synchronizeWarehouses();
  87.  
  88.             $console->syncWarehousesComplete();
  89.             $log->syncWarehousesEnd();
  90.         } catch (\Exception $e) {
  91.             $log->syncWarehousesFailed();
  92.             $log->syncException($e);
  93.         }
  94.  
  95.         $console->syncComplete();
  96.         $log->syncEnd();
  97.     }
  98.  
  99.     private function checkDifference(): bool
  100.     {
  101.         $this->getCities();
  102.         $this->getWarehouses();
  103.  
  104.         $r1 = $this->checkDifferenceCities();
  105.         $r2 = $this->checkDifferenceWarehouses();
  106.  
  107.         $this->log->checkingDiff();
  108.  
  109.         if (!$r1 || !$r2) {
  110.             throw new InvalidArgumentException('Sync fails via big difference among API and DB.');
  111.         }
  112.  
  113.         return true;
  114.     }
  115.  
  116.     /**
  117.      * @return array
  118.      */
  119.     private function getCities(): array
  120.     {
  121.         $cities = $this->api->getCities();
  122.         $this->citiesApi = $cities;
  123.  
  124.         return $cities;
  125.     }
  126.  
  127.     /**
  128.      * @param string $ref
  129.      * @return array
  130.      */
  131.     private function getWarehouses(string $ref = null): array
  132.     {
  133.         $warehouses = $this->api->getWarehouses($ref);
  134.         $this->warehousesApi = $warehouses;
  135.  
  136.         return $warehouses;
  137.     }
  138.  
  139.     private function checkDifferenceCities(): bool
  140.     {
  141.         $cntApi = array_key_exists('info', $this->citiesApi) ? $this->citiesApi['info']['totalCount'] : 0;
  142.         $cntDB = $this->em->getRepository(City::class)->countCities();
  143.  
  144.         return $this->differenceLogic($cntApi, $cntDB, 'cities');
  145.     }
  146.  
  147.     private function checkDifferenceWarehouses(): bool
  148.     {
  149.         $cntApi = array_key_exists('info', $this->warehousesApi) ? $this->warehousesApi['info']['totalCount'] : 0;
  150.         $cntDB = $this->em->getRepository(Warehouse::class)->countWarehouses();
  151.  
  152.         return $this->differenceLogic($cntApi, $cntDB, 'warehouses');
  153.     }
  154.  
  155.     private function differenceLogic(int $cntApi, int $cntDB, string $type): bool
  156.     {
  157.         $this->log->syncDifference($type, $cntDB, $cntApi);
  158.  
  159.         if ($this->percent * $cntDB > $cntApi) {
  160.             return false;
  161.         }
  162.  
  163.         return true;
  164.     }
  165.  
  166.     private function synchronizeCities(): bool
  167.     {
  168.         $this->setCitiesDB();
  169.         $citiesApi = $this->transformApiCities($this->citiesApi);
  170.         $citiesDB = $this->transformDBCities();
  171.  
  172.         $complexArray = $this->resolveCitiesDifference($citiesApi, $citiesDB);
  173.         $add = $complexArray['add'];
  174.         $update = $complexArray['update'];
  175.         $remove = $complexArray['remove'];
  176.  
  177.         $this->synchronizeCitiesDB($add, $update, $remove);
  178.  
  179.         $this->em->flush();
  180.         $this->log->unLoadLogStack();
  181.  
  182.         return true;
  183.     }
  184.  
  185.     private function synchronizeWarehouses(): bool
  186.     {
  187.         $this->setCitiesDB();
  188.         $this->setWarehousesDB();
  189.         $warehousesApi = $this->transformApiWarehouses();
  190.         $warehousesDB = $this->transformDBWarehouses();
  191.  
  192.         $complexArray = $this->resolveWarehousesDifference($warehousesApi, $warehousesDB);
  193.         $add = $complexArray['add'];
  194.         $update = $complexArray['update'];
  195.         $remove = $complexArray['remove'];
  196.  
  197.         $this->synchronizeWarehousesDB($add, $update, $remove);
  198.  
  199.         $this->em->flush();
  200.         $this->log->unLoadLogStack();
  201.  
  202.         return true;
  203.     }
  204.  
  205.     public function transformApiCities($apiAnswer): array
  206.     {
  207.         $transformed = [];
  208.         if (!is_array($apiAnswer['data'])) {
  209.             throw new \InvalidArgumentException('No cities data from api');
  210.         }
  211.  
  212.         foreach ($apiAnswer['data'] as $city) {
  213.             $transformed[$city['DescriptionRu']] = $city['DescriptionRu'];
  214.         }
  215.         return $transformed;
  216.     }
  217.  
  218.  
  219.     private function transformDBCities(): array
  220.     {
  221.         $citiesDB = $this->em->getRepository(City::class)->findAll();
  222.         $transformed = [];
  223.  
  224.         /** @var City $city */
  225.         foreach ($citiesDB as $city) {
  226.             $transformed[$city->getId()] = $city->getName();
  227.         }
  228.  
  229.         return $transformed;
  230.     }
  231.  
  232.     private function transformApiWarehouses(): array
  233.     {
  234.         $transformed = [];
  235.         if (!is_array($this->warehousesApi['data'])) {
  236.             throw new \InvalidArgumentException('No warehouses data from api');
  237.         }
  238.  
  239.         foreach ($this->warehousesApi['data'] as $warehouse) {
  240.             $transformed[$warehouse['Ref']] = [
  241.                 'city_ref' => $warehouse['CityRef'],
  242.                 'name' => $warehouse['DescriptionRu'],
  243.             ];
  244.         }
  245.         return $transformed;
  246.     }
  247.  
  248.     /**
  249.      * @return array
  250.      */
  251.     private function transformDBWarehouses(): array
  252.     {
  253.         $warehousesDB = $this->em->getRepository(Warehouse::class)->findAll();
  254.         $transformed = [];
  255.  
  256.         /** @var Warehouse $warehouse */
  257.         foreach ($warehousesDB as $warehouse) {
  258.             $transformed[$warehouse->getId()] = [
  259.                 'city_ref' => $warehouse->getCity()->getId(),
  260.                 'name' => $warehouse->getName(),
  261.             ];
  262.         }
  263.  
  264.         return $transformed;
  265.     }
  266.  
  267.     private function setCitiesDB(): void
  268.     {
  269.         $citiesDB = $this->em->getRepository(City::class)->findAll();
  270.         $citiesStatic = [];
  271.  
  272.         /** @var City $city */
  273.         foreach ($citiesDB as $city) {
  274.             $citiesStatic[$city->getId()] = $city;
  275.         }
  276.         $this->citiesDB = $citiesStatic;
  277.     }
  278.  
  279.     private function setWarehousesDB(): void
  280.     {
  281.         $warehousesDB = $this->em->getRepository(Warehouse::class)->findAll();
  282.         $warehousesStatic = [];
  283.  
  284.         /** @var Warehouse $warehouse */
  285.         foreach ($warehousesDB as $warehouse) {
  286.             $warehousesStatic[$warehouse->getId()] = $warehouse;
  287.         }
  288.         $this->warehousesDB = $warehousesStatic;
  289.     }
  290.  
  291.     /**
  292.      * @param array $citiesApi
  293.      * @param array $citiesDB
  294.      * @return array
  295.      */
  296.     private function resolveCitiesDifference(array $citiesApi, array $citiesDB): array
  297.     {
  298.         $add = $update = $remove = [];
  299.         foreach ($citiesApi as $key => $name) {
  300.             if (array_key_exists($key, $citiesDB)) {
  301.                 if ($citiesDB[$key] != $name) {
  302.                     $update[$key] = $name;
  303.                 }
  304.             } else {
  305.                 $add[$key] = $name;
  306.             }
  307.         }
  308.  
  309.         foreach ($citiesDB as $key => $name) {
  310.             if (!array_key_exists($key, $citiesApi)) {
  311.                 $remove[$key] = $name;
  312.             }
  313.         }
  314.         return [
  315.             'add' => $add,
  316.             'update' => $update,
  317.             'remove' => $remove,
  318.         ];
  319.     }
  320.  
  321.     /**
  322.      * @param array $warehousesApi
  323.      * @param array $warehousesDB
  324.      * @return array
  325.      */
  326.     private function resolveWarehousesDifference(array $warehousesApi, array $warehousesDB): array
  327.     {
  328.         $add = $update = $remove = [];
  329.         foreach ($warehousesApi as $key => $data) {
  330.             if (array_key_exists($key, $warehousesDB)) {
  331.                 if ($warehousesDB[$key]['name'] != $data['name']) {
  332.                     $update[$key] = $data['name'];
  333.                 }
  334.             } else {
  335.                 $add[$key] = [
  336.                     'city_ref' => $data['city_ref'],
  337.                     'name' => $data['name'],
  338.                 ];
  339.             }
  340.         }
  341.  
  342.         foreach ($warehousesDB as $key => $data) {
  343.             if (!array_key_exists($key, $warehousesApi)) {
  344.                 $remove[$key] = $data['name'];
  345.             }
  346.         }
  347.  
  348.         return [
  349.             'add' => $add,
  350.             'update' => $update,
  351.             'remove' => $remove,
  352.         ];
  353.     }
  354.  
  355.     /**
  356.      * @param array $add
  357.      * @param array $update
  358.      * @param array $remove
  359.      * @return bool
  360.      */
  361.     private function synchronizeCitiesDB(array $add, array $update, array $remove): bool
  362.     {
  363.         $em = $this->em;
  364.         $log = $this->log;
  365.  
  366.         foreach ($add as $ref => $name) {
  367.             $em->persist(new City($ref, $name));
  368.             $this->log->addLogToStack('info', $log->messageAddCity($ref));
  369.         }
  370.  
  371.         foreach ($update as $ref => $name) {
  372.             /** @var City $city */
  373.             $city = $this->citiesDB[$ref];
  374.             $city->setName($name);
  375.             $em->persist($city);
  376.             $this->log->addLogToStack('info', $log->messageUpdateCity($ref));
  377.         }
  378.  
  379.         foreach ($remove as $ref => $name) {
  380.             /** @var City $city */
  381.             $city = $this->citiesDB[$ref];
  382.             $em->remove($city);
  383.             $this->log->addLogToStack('info', $log->messageRemoveCity($ref));
  384.         }
  385.  
  386.         return true;
  387.     }
  388.  
  389.     /**
  390.      * @param array $add
  391.      * @param array $update
  392.      * @param array $remove
  393.      * @return bool
  394.      */
  395.     private function synchronizeWarehousesDB(array $add, array $update, array $remove): bool
  396.     {
  397.         $em = $this->em;
  398.         $log = $this->log;
  399.  
  400.         foreach ($add as $ref => $data) {
  401.             /** @var City $city */
  402.             $city = $this->citiesDB[$data['city_ref']];
  403.             $em->persist(new Warehouse($ref, $data['name'], $city));
  404.             $this->log->addLogToStack('info', $log->messageAddWarehouse($ref));
  405.         }
  406.  
  407.         foreach ($update as $ref => $name) {
  408.             /** @var Warehouse $warehouse */
  409.             $warehouse = $this->warehousesDB[$ref];
  410.             $warehouse->setName($name);
  411.             $em->persist($warehouse);
  412.             $this->log->addLogToStack('info', $log->messageUpdateWarehouse($ref));
  413.         }
  414.  
  415.         foreach ($remove as $ref => $name) {
  416.             /** @var Warehouse $warehouse */
  417.             $warehouse = $this->warehousesDB[$ref];
  418.             $em->remove($warehouse);
  419.             $this->log->addLogToStack('info', $log->messageRemoveWarehouse($ref));
  420.         }
  421.  
  422.         return true;
  423.     }
  424. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement