Completed
Push — 1.10 ( 3bcec0...1a0641 )
by
unknown
08:47
created

MagentoSyncProcessor::getSyncInterval()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 11
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 6
nc 2
nop 0
1
<?php
2
3
namespace OroCRM\Bundle\MagentoBundle\Provider;
4
5
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
6
7
use Doctrine\Common\Persistence\ManagerRegistry;
8
9
use Oro\Bundle\IntegrationBundle\Entity\Channel as Integration;
10
use Oro\Bundle\ImportExportBundle\Processor\ProcessorRegistry;
11
use Oro\Bundle\IntegrationBundle\ImportExport\Job\Executor;
12
use Oro\Bundle\IntegrationBundle\Logger\LoggerStrategy;
13
use Oro\Bundle\IntegrationBundle\Manager\TypesRegistry;
14
use Oro\Bundle\IntegrationBundle\Provider\SyncProcessor;
15
use Oro\Bundle\IntegrationBundle\Entity\Repository\ChannelRepository;
16
use Oro\Bundle\IntegrationBundle\Entity\Status;
17
18
use OroCRM\Bundle\MagentoBundle\Entity\MagentoSoapTransport;
19
20
class MagentoSyncProcessor extends SyncProcessor
21
{
22
    const SYNCED_TO = 'initialSyncedTo';
23
    const SKIP_STATUS = 'skip';
24
    const INTERVAL = 'initialSyncInterval';
25
    const INCREMENTAL_INTERVAL = 'incrementalInterval';
26
    const START_SYNC_DATE = 'start_sync_date';
27
28
    /** @var array|null */
29
    protected $bundleConfiguration;
30
31
    /** @var string */
32
    protected $channelClassName;
33
34
    /**
35
     * @param ManagerRegistry $doctrineRegistry
36
     * @param ProcessorRegistry $processorRegistry
37
     * @param Executor $jobExecutor
38
     * @param TypesRegistry $registry
39
     * @param EventDispatcherInterface $eventDispatcher
40
     * @param LoggerStrategy $logger
41
     * @param array $bundleConfiguration
42
     */
43
    public function __construct(
44
        ManagerRegistry $doctrineRegistry,
45
        ProcessorRegistry $processorRegistry,
46
        Executor $jobExecutor,
47
        TypesRegistry $registry,
48
        EventDispatcherInterface $eventDispatcher,
49
        LoggerStrategy $logger = null,
50
        array $bundleConfiguration = null
51
    ) {
52
        parent::__construct(
53
            $doctrineRegistry,
54
            $processorRegistry,
55
            $jobExecutor,
56
            $registry,
57
            $eventDispatcher,
58
            $logger
59
        );
60
61
        $this->bundleConfiguration = $bundleConfiguration;
62
    }
63
64
    /**
65
     * @param string $channelClassName
66
     */
67
    public function setChannelClassName($channelClassName)
68
    {
69
        $this->channelClassName = $channelClassName;
70
    }
71
72
    /**
73
     * @return \DateInterval
74
     */
75
    protected function getSyncInterval()
76
    {
77
        if (empty($this->bundleConfiguration['sync_settings']['import_step_interval'])) {
78
            throw new \InvalidArgumentException('Option "import_step_interval" is missing');
79
        }
80
81
        $syncInterval = $this->bundleConfiguration['sync_settings']['import_step_interval'];
82
        $interval = \DateInterval::createFromDateString($syncInterval);
83
84
        return $interval;
85
    }
86
87
    /**
88
     * {@inheritdoc}
89
     */
90
    protected function processConnectors(Integration $integration, array $parameters = [], callable $callback = null)
91
    {
92
        // Pass interval to connectors for further filters creation
93
        $interval = $this->getSyncInterval();
94
        $parameters[self::INCREMENTAL_INTERVAL] = $interval;
95
96
        // Collect initial connectors
97
        $connectors = $this->getTypesOfConnectorsToProcess($integration, $callback);
98
99
        /** @var \DateTime[] $connectorsSyncedTo */
100
        $connectorsSyncedTo = [];
101
        foreach ($connectors as $connector) {
102
            $connectorsSyncedTo[$connector] = $this->getConnectorSyncedTo($integration, $connector);
103
        }
104
105
        $processedConnectorStatuses = [];
106
        $isSuccess = true;
107
108
        foreach ($connectors as $connector) {
109
            $this->logger->info(
110
                sprintf(
111
                    'Syncing connector %s starting %s interval %s',
112
                    $connector,
113
                    $connectorsSyncedTo[$connector]->format('Y-m-d H:i:s'),
114
                    $interval->format('%d days')
115
                )
116
            );
117
118
            try {
119
                $realConnector = $this->getRealConnector($integration, $connector);
120
                if (!$this->isConnectorAllowed($realConnector, $integration, $processedConnectorStatuses)) {
121
                    continue;
122
                }
123
                // Pass synced to for further filters creation
124
                $parameters = array_merge(
125
                    $parameters,
126
                    [self::SYNCED_TO => clone $connectorsSyncedTo[$connector]]
127
                );
128
129
                $status = $this->processIntegrationConnector(
130
                    $integration,
131
                    $realConnector,
132
                    $parameters
133
                );
134
                // Move sync date into future by interval value
135
                $connectorsSyncedTo[$connector] = $this->getIncrementalSyncedTo(
136
                    $connectorsSyncedTo[$connector],
137
                    $interval
138
                );
139
                $isSuccess = $isSuccess && $this->isIntegrationConnectorProcessSuccess($status);
140
141
                if ($isSuccess) {
142
                    // Save synced to date for connector
143
                    $syncedTo = $connectorsSyncedTo[$connector];
144
                    $this->updateSyncedTo($integration, $connector, $syncedTo);
145
                }
146
            } catch (\Exception $e) {
147
                $isSuccess = false;
148
                $this->logger->critical($e->getMessage(), ['exception' => $e]);
149
            }
150
        }
151
152
        return $isSuccess;
153
    }
154
155
    /**
156
     * @param $syncedTo
157
     * @param $interval
158
     * @return mixed
159
     */
160
    protected function getIncrementalSyncedTo($syncedTo, $interval)
161
    {
162
        $syncedTo->add($interval);
163
        $now = new \DateTime('now', new \DateTimeZone('UTC'));
164
        if ($syncedTo > $now) {
165
            return $now;
166
        }
167
168
        return $syncedTo;
169
    }
170
171
    /**
172
     * @param Integration $integration
173
     * @param string $connector
174
     * @return \DateTime
175
     */
176
    protected function getConnectorSyncedTo(Integration $integration, $connector)
177
    {
178
        $latestSyncedTo = $this->getSyncedTo($integration, $connector);
179
        if ($latestSyncedTo === false) {
180
            return clone $this->getInitialSyncStartDate($integration);
181
        }
182
183
        return clone $latestSyncedTo;
184
    }
185
186
    /**
187
     * @param Integration $integration
188
     * @return \DateTime
189
     */
190
    protected function getInitialSyncStartDate(Integration $integration)
191
    {
192
        if ($this->isInitialSyncStarted($integration)) {
193
            /** @var MagentoSoapTransport $transport */
194
            $transport = $integration->getTransport();
195
196
            return $transport->getInitialSyncStartDate();
197
        } else {
198
            return new \DateTime('now', new \DateTimeZone('UTC'));
199
        }
200
    }
201
202
    /**
203
     * @param Integration $integration
204
     * @return bool
205
     */
206
    protected function isInitialSyncStarted(Integration $integration)
207
    {
208
        /** @var MagentoSoapTransport $transport */
209
        $transport = $integration->getTransport();
210
211
        return (bool)$transport->getInitialSyncStartDate();
212
    }
213
214
    /**
215
     * @param Integration $integration
216
     * @param string $connector
217
     * @return bool|\DateTime
218
     */
219
    protected function getSyncedTo(Integration $integration, $connector)
220
    {
221
        $lastStatus = $this->getLastStatusForConnector($integration, $connector, Status::STATUS_COMPLETED);
222 View Code Duplication
        if ($lastStatus) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
223
            $statusData = $lastStatus->getData();
224
            if (!empty($statusData[static::SYNCED_TO])) {
225
                return \DateTime::createFromFormat(
226
                    \DateTime::ISO8601,
227
                    $statusData[static::SYNCED_TO],
228
                    new \DateTimeZone('UTC')
229
                );
230
            }
231
        }
232
233
        return false;
234
    }
235
236
    /**
237
     * @param Integration $integration
238
     * @param string $connector
239
     * @param int|null $code
240
     * @return null|Status
241
     */
242
    protected function getLastStatusForConnector(Integration $integration, $connector, $code = null)
243
    {
244
        $status = $this->getChannelRepository()->getLastStatusForConnector($integration, $connector, $code);
245
        if ($status) {
246
            $statusData = $status->getData();
247
            if (!empty($statusData[self::SKIP_STATUS])) {
248
                return null;
249
            }
250
        }
251
252
        return $status;
253
    }
254
255
    /**
256
     * @return ChannelRepository
257
     */
258
    protected function getChannelRepository()
259
    {
260
        if (!$this->channelClassName) {
261
            throw new \InvalidArgumentException('Channel class option is missing');
262
        }
263
264
        return $this->doctrineRegistry->getRepository($this->channelClassName);
265
    }
266
267
    /**
268
     * @param Integration $integration
269
     * @param string $connector
270
     * @param \DateTime $syncedTo
271
     */
272
    protected function updateSyncedTo(Integration $integration, $connector, \DateTime $syncedTo)
273
    {
274
        $formattedSyncedTo = $syncedTo->format(\DateTime::ISO8601);
275
276
        $lastStatus = $this->getLastStatusForConnector($integration, $connector, Status::STATUS_COMPLETED);
277
        $statusData = $lastStatus->getData();
278
        $statusData[self::SYNCED_TO] = $formattedSyncedTo;
279
        $lastStatus->setData($statusData);
280
281
        $this->addConnectorStatusAndFlush($integration, $lastStatus);
0 ignored issues
show
Bug introduced by
It seems like $lastStatus defined by $this->getLastStatusForC...atus::STATUS_COMPLETED) on line 276 can be null; however, Oro\Bundle\IntegrationBu...nnectorStatusAndFlush() does not accept null, maybe add an additional type check?

Unless you are absolutely sure that the expression can never be null because of other conditions, we strongly recommend to add an additional type check to your code:

/** @return stdClass|null */
function mayReturnNull() { }

function doesNotAcceptNull(stdClass $x) { }

// With potential error.
function withoutCheck() {
    $x = mayReturnNull();
    doesNotAcceptNull($x); // Potential error here.
}

// Safe - Alternative 1
function withCheck1() {
    $x = mayReturnNull();
    if ( ! $x instanceof stdClass) {
        throw new \LogicException('$x must be defined.');
    }
    doesNotAcceptNull($x);
}

// Safe - Alternative 2
function withCheck2() {
    $x = mayReturnNull();
    if ($x instanceof stdClass) {
        doesNotAcceptNull($x);
    }
}
Loading history...
282
    }
283
}
284