Completed
Push — 3.2 ( 8c2d5f...e78c57 )
by
unknown
08:28 queued 06:51
created

ZohoDatabasePusher::pushDataToZoho()   D

Complexity

Conditions 17
Paths 26

Size

Total Lines 152

Duplication

Lines 47
Ratio 30.92 %

Importance

Changes 0
Metric Value
dl 47
loc 152
rs 4.1733
c 0
b 0
f 0
cc 17
nc 26
nop 2

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Wabel\Zoho\CRM\Copy;
4
5
use Doctrine\DBAL\Connection;
6
use Psr\Log\LoggerInterface;
7
use Psr\Log\NullLogger;
8
use Wabel\Zoho\CRM\AbstractZohoDao;
9
use Wabel\Zoho\CRM\Service\EntitiesGeneratorService;
10
use Wabel\Zoho\CRM\ZohoBeanInterface;
11
use zcrmsdk\crm\api\response\EntityResponse;
12
13
/**
14
 * Description of ZohoDatabasePusher.
15
 *
16
 * @author rbergina
17
 */
18
class ZohoDatabasePusher
19
{
20
    /**
21
     * @var Connection
22
     */
23
    private $connection;
24
25
    /**
26
     * @var LoggerInterface
27
     */
28
    private $logger;
29
30
    /**
31
     * @var string
32
     */
33
    private $prefix;
34
35
    /**
36
     * @param Connection $connection
37
     * @param int $apiLimitInsertUpdateDelete
38
     * @param string $prefix
39
     * @param LoggerInterface $logger
40
     */
41
    public function __construct(Connection $connection, $apiLimitInsertUpdateDelete = 100, $prefix = 'zoho_', LoggerInterface $logger = null)
42
    {
43
        $this->connection = $connection;
44
        $this->prefix = $prefix;
45
        if ($logger === null) {
46
            $this->logger = new NullLogger();
47
        } else {
48
            $this->logger = $logger;
49
        }
50
        $this->apiLimitInsertUpdateDelete = $apiLimitInsertUpdateDelete;
51
        if ($apiLimitInsertUpdateDelete === null) {
52
            $this->apiLimitInsertUpdateDelete = 100;
53
        }
54
    }
55
56
    /**
57
     * @var int
58
     */
59
    private $apiLimitInsertUpdateDelete;
60
61
    /**
62
     * @param AbstractZohoDao $zohoDao
63
     * @param bool $update
64
     * @return int
65
     */
66
    private function countElementInTable(AbstractZohoDao $zohoDao, $update = false)
67
    {
68
        $tableName = ZohoDatabaseHelper::getTableName($zohoDao, $this->prefix);
69
        if ($update) {
70
            return (int)$this->connection->executeQuery('SELECT COUNT(DISTINCT uid) AS nb FROM `local_update` WHERE table_name LIKE :tableName AND error IS NULL', ['tableName' => $tableName])->fetchColumn();
71
        }
72
        return (int)$this->connection->executeQuery('SELECT COUNT(uid) AS nb FROM `local_insert` WHERE table_name LIKE :tableName AND error IS NULL', ['tableName' => $tableName])->fetchColumn();
73
    }
74
75
    /**
76
     * Insert or Update rows.
77
     *
78
     * @param AbstractZohoDao $zohoDao
79
     */
80
    public function pushDataToZoho(AbstractZohoDao $zohoDao, $update = false)
81
    {
82
        $localTable = $update ? 'local_update' : 'local_insert';
83
        $tableName = ZohoDatabaseHelper::getTableName($zohoDao, $this->prefix);
84
        $countToPush = $this->countElementInTable($zohoDao, $update);
85
        $this->logger->notice($countToPush . ' records to ' . ($update ? 'update' : 'insert') . ' into Zoho for module ' . $zohoDao->getPluralModuleName());
86
        if ($countToPush) {
87
            do {
88
                $rowsDeleted = [];
89
                $zohoBeans = [];
90
                //@see https://www.zoho.com/crm/help/api/v2/#ra-update-records
91
                //To optimize your API usage, get maximum 200 records with each request and insert, update or delete maximum 100 records with each request.
92
93
                if ($update) {
94
                    $recordsToUpdateQuery = $this->connection->createQueryBuilder();
95
                    $recordsToUpdateQuery
96
                        ->select('DISTINCT table_name, uid')
97
                        ->from($localTable)
98
                        ->where('error IS NULL')
99
                        ->andWhere('table_name = :table_name')
100
                        ->setMaxResults($this->apiLimitInsertUpdateDelete)
101
                        ->setParameters([
102
                            'table_name' => $tableName
103
                        ]);
104
                    $recordsToUpdateResults = $recordsToUpdateQuery->execute()->fetchAll();
105
                    $this->logger->info(sprintf('Processing %s records to update...', count($recordsToUpdateResults)));
106
                    foreach ($recordsToUpdateResults as $result) {
107
                        $recordQuery = $this->connection->createQueryBuilder();
108
                        $recordQuery
109
                            ->select('*')
110
                            ->from($tableName)
111
                            ->where('uid = :uid')
112
                            ->setParameters([
113
                                'uid' => $result['uid']
114
                            ]);
115
                        $record = $recordQuery->execute()->fetch();
116
117 View Code Duplication
                        if (!$record) {
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...
118
                            $errorMessage = sprintf('Impossible to find row with uid %s in the table %s', $result['uid'], $tableName);
119
                            $this->logger->warning($errorMessage);
120
                            $this->connection->update($localTable, [
121
                                'error' => $errorMessage,
122
                                'errorTime' => date('Y-m-d H:i:s'),
123
                            ], [
124
                                'uid' => $result['uid'],
125
                                'table_name' => $tableName
126
                            ]);
127
                            continue;
128
                        }
129
130 View Code Duplication
                        if (isset($zohoBeans[$record['uid']])) {
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...
131
                            $zohoBean = $zohoBeans[$record['uid']];
132
                        } else {
133
                            $zohoBean = $zohoDao->create();
134
                        }
135
136
                        if ($record['id'] && !$zohoBean->getZohoId()) {
137
                            $zohoBean->setZohoId($record['id']);
138
                        }
139
140
                        $fieldsUpdatedQuery = $this->connection->createQueryBuilder();
141
                        $fieldsUpdatedQuery
142
                            ->select('field_name')
143
                            ->from($localTable)
144
                            ->where('uid = :uid')
145
                            ->andWhere('table_name = :table_name')
146
                            ->andWhere('error IS NULL')
147
                            ->setParameters([
148
                                'uid' => $result['uid'],
149
                                'table_name' => $tableName,
150
                            ]);
151
                        $fieldsUpdatedResults = $fieldsUpdatedQuery->execute()->fetchAll();
152
153
                        foreach ($fieldsUpdatedResults as $fieldResults) {
154
                            $columnName = $fieldResults['field_name'];
155
                            if (isset($record[$columnName])) {
156
                                $this->updateDataZohoBean($zohoDao, $zohoBean, $columnName, $record[$columnName]);
157 View Code Duplication
                            } else {
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...
158
                                $errorMessage = sprintf('Impossible to find the column %s for row with uid %s in the table %s', $columnName, $result['uid'], $tableName);
159
                                $this->logger->warning($errorMessage);
160
                                $this->connection->update($localTable, [
161
                                    'error' => $errorMessage,
162
                                    'errorTime' => date('Y-m-d H:i:s'),
163
                                ], [
164
                                    'uid' => $result['uid'],
165
                                    'table_name' => $tableName,
166
                                    'field_name' => $columnName
167
                                ]);
168
                                continue;
169
                            }
170
                        }
171
172
                        $this->logger->debug(sprintf('Updated row %s (id: \'%s\') from table %s added in queue to be pushed.', $record['uid'], $record['id'], $tableName));
173
                        $zohoBeans[$record['uid']] = $zohoBean;
174
                        $rowsDeleted[] = $record['uid'];
175
                    }
176
                } else {
177
                    $recordsToInsertQuery = $this->connection->createQueryBuilder();
178
                    $recordsToInsertQuery
179
                        ->select('DISTINCT table_name, uid')
180
                        ->from($localTable)
181
                        ->where('error IS NULL')
182
                        ->andWhere('table_name = :table_name')
183
                        ->setMaxResults($this->apiLimitInsertUpdateDelete)
184
                        ->setParameters([
185
                            'table_name' => $tableName
186
                        ]);
187
                    $recordsToInsertResults = $recordsToInsertQuery->execute()->fetchAll();
188
                    $this->logger->info(sprintf('Processing %s records to insert...', count($recordsToInsertResults)));
189
                    foreach ($recordsToInsertResults as $result) {
190
                        $recordQuery = $this->connection->createQueryBuilder();
191
                        $recordQuery
192
                            ->select('*')
193
                            ->from($tableName)
194
                            ->where('uid = :uid')
195
                            ->setParameters([
196
                                'uid' => $result['uid']
197
                            ]);
198
                        $record = $recordQuery->execute()->fetch();
199
200 View Code Duplication
                        if (!$record) {
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...
201
                            $errorMessage = sprintf('Impossible to find row with uid %s in the table %s', $result['uid'], $tableName);
202
                            $this->logger->warning($errorMessage);
203
                            $this->connection->update($localTable, [
204
                                'error' => $errorMessage,
205
                                'errorTime' => date('Y-m-d H:i:s'),
206
                            ], [
207
                                'uid' => $result['uid'],
208
                                'table_name' => $tableName
209
                            ]);
210
                            continue;
211
                        }
212
213 View Code Duplication
                        if (isset($zohoBeans[$record['uid']])) {
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...
214
                            $zohoBean = $zohoBeans[$record['uid']];
215
                        } else {
216
                            $zohoBean = $zohoDao->create();
217
                        }
218
219
                        $this->logger->debug(sprintf('New row with uid %s from table %s added in queue to be pushed.', $record['uid'], $tableName));
220
                        $this->insertDataZohoBean($zohoDao, $zohoBean, $record);
221
                        $zohoBeans[$record['uid']] = $zohoBean;
222
                        $rowsDeleted[] = $record['uid'];
223
                    }
224
                }
225
                if (count($zohoBeans)) {
226
                    $this->sendDataToZohoCleanLocal($zohoDao, $zohoBeans, $rowsDeleted, $update);
227
                }
228
                $countToPush = $this->countElementInTable($zohoDao, $update);
229
            } while ($countToPush > 0);
230
        }
231
    }
232
233
    /**
234
     * @param AbstractZohoDao $zohoDao
235
     * @param ZohoBeanInterface[] $zohoBeans
236
     * @param string[] $rowsDeleted
237
     * @param bool $update
238
     */
239
    private function sendDataToZohoCleanLocal(AbstractZohoDao $zohoDao, array $zohoBeans, $rowsDeleted, $update = false)
0 ignored issues
show
Unused Code introduced by
The parameter $rowsDeleted is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
240
    {
241
        $local_table = $update ? 'local_update' : 'local_insert';
242
        $tableName = ZohoDatabaseHelper::getTableName($zohoDao, $this->prefix);
243
        $entityResponses = $zohoDao->save($zohoBeans);
244
        $responseKey = 0;
245
        foreach ($zohoBeans as $uid => $zohoBean) {
246
            $response = $entityResponses[$responseKey]->getResponseJSON();
247
            if (strtolower($response['code']) === 'success') {
248
                if ($update) {
249
                    $this->logger->debug(sprintf('Updated successfully the record with uid %s (id \'%s\') from the table %s', $uid, $zohoBean->getZohoId(), $tableName));
250
                    $this->connection->executeQuery(
251
                        'DELETE FROM local_update WHERE uid LIKE :uid AND table_name = :table_name AND error IS NULL',
252
                        [
253
                            'uid' => $uid,
254
                            'table_name' => $tableName
255
                        ]
256
                    );
257
                } else {
258
                    $countResult = (int)$this->connection->fetchColumn('select count(id) from ' . $tableName . ' where id = :id', ['id' => $zohoBean->getZohoId()]);
259
                    //If the sent data were duplicates Zoho can merged so we need to check if the Zoho ID already exist.
260
                    if ($countResult === 0) {
261
                        // ID not exist we can update the new row with the Zoho ID
262
                        $this->connection->beginTransaction();
263
                        $this->connection->update($tableName, ['id' => $zohoBean->getZohoId()], ['uid' => $uid]);
264
                        $this->connection->delete('local_insert', ['table_name' => $tableName, 'uid' => $uid]);
265
                        $this->connection->commit();
266
                        $this->logger->debug(sprintf('Inserted successfully the record with uid %s (id \'%s\') from the table %s', $uid, $zohoBean->getZohoId(), $tableName));
267
                    } else {
268
                        //ID already exist we need to delete the duplicate row.
269
                        $this->connection->beginTransaction();
270
                        $this->connection->delete($tableName, ['uid' => $uid]);
271
                        $this->connection->delete('local_insert', ['table_name' => $tableName, 'uid' => $uid]);
272
                        $this->connection->commit();
273
                        $this->logger->warning(sprintf('Duplicate record found when inserting record with uid %s from the table %s. ID updated: %s. UID deleted: %s', $uid, $tableName, $zohoBean->getZohoId(), $uid));
274
                    }
275
                }
276
            } else {
277
                $errorMessage = sprintf('An error occurred when %s record with uid %s from table %s into Zoho: %s', ($update ? 'updating' : 'inserting'), $uid, $tableName, json_encode($response));
278
                $this->logger->error($errorMessage);
279
                $this->connection->update($local_table, [
280
                    'error' => $errorMessage,
281
                    'errorTime' => date('Y-m-d H:i:s')
282
                ], [
283
                    'uid' => $uid,
284
                    'table_name' => $tableName
285
                ]);
286
            }
287
            $responseKey++;
288
        }
289
    }
290
291
    /**
292
     * Insert data to bean in order to insert zoho records.
293
     *
294
     * @param AbstractZohoDao $dao
295
     * @param ZohoBeanInterface $zohoBean
296
     * @param array $row
297
     */
298 View Code Duplication
    private function insertDataZohoBean(AbstractZohoDao $dao, ZohoBeanInterface $zohoBean, array $row)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
299
    {
300
        foreach ($row as $columnName => $columnValue) {
301
            $fieldMethod = $dao->getFieldFromFieldName($columnName);
302
            if (!in_array($columnName, EntitiesGeneratorService::$defaultDateFields) && $fieldMethod
303
                && (!in_array($columnName, ['id', 'uid'])) && !is_null($columnValue)
304
            ) {
305
                $type = $fieldMethod->getType();
306
                $value = $this->formatValueToBeans($type, $columnValue);
307
                $setterMethod = $fieldMethod->getSetter();
308
                $zohoBean->{$setterMethod}($value);
309
            }
310
        }
311
    }
312
313
    /**
314
     * Insert data to bean in order to update zoho records.
315
     *
316
     * @param ZohoBeanInterface $zohoBean
317
     * @param array $fieldsMatching
0 ignored issues
show
Bug introduced by
There is no parameter named $fieldsMatching. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
318
     * @param type $columnName
319
     * @param type $valueDb
320
     */
321 View Code Duplication
    private function updateDataZohoBean(AbstractZohoDao $dao, ZohoBeanInterface $zohoBean, $columnName, $valueDb)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
322
    {
323
        $fieldMethod = $dao->getFieldFromFieldName($columnName);
324
        if (!in_array($columnName, EntitiesGeneratorService::$defaultDateFields) && $fieldMethod
325
            && !in_array($columnName, ['id', 'uid'])
326
        ) {
327
            $type = $fieldMethod->getType();
328
            $value = is_null($valueDb) ? $valueDb : $this->formatValueToBeans($type, $valueDb);
329
            $setterMethod = $fieldMethod->getSetter();
330
            $zohoBean->{$setterMethod}($value);
331
        }
332
    }
333
334
    /**
335
     * Change the value to the good format.
336
     *
337
     * @param string $type
338
     * @param mixed $value
339
     *
340
     * @return mixed
341
     */
342
    private function formatValueToBeans($type, $value)
343
    {
344
        switch ($type) {
345
            case 'date':
346
                $value = \DateTime::createFromFormat('Y-m-d', $value) ?: null;
347
                break;
348
            case 'datetime':
349
                $value = \DateTime::createFromFormat('Y-m-d H:i:s', $value) ?: null;
350
                break;
351
            case 'boolean' :
352
                $value = (bool)$value;
353
                break;
354
            case 'percent' :
355
                $value = (int)$value;
356
                break;
357
            case 'double' :
358
                $value = number_format($value, 2);
359
                break;
360
            case 'multiselectlookup':
361
            case 'multiuserlookup':
362
            case 'multiselectpicklist':
363
                $value = explode(';', $value);
364
                break;
365
        }
366
367
        return $value;
368
    }
369
370
    /**
371
     * Run deleted rows to Zoho : local_delete.
372
     *
373
     * @param AbstractZohoDao $zohoDao
374
     */
375
    public function pushDeletedRows(AbstractZohoDao $zohoDao)
376
    {
377
        $localTable = 'local_delete';
378
        $tableName = ZohoDatabaseHelper::getTableName($zohoDao, $this->prefix);
379
        $statement = $this->connection->createQueryBuilder();
380
        $statement->select('l.id')
381
            ->from($localTable, 'l')
382
            ->where('l.table_name=:table_name')
383
            ->setParameters(
384
                [
385
                    'table_name' => $tableName,
386
                ]
387
            );
388
        $results = $statement->execute();
389
        while ($row = $results->fetch()) {
390
            $zohoDao->delete($row['id']);
391
            $this->connection->delete($localTable, ['table_name' => $tableName, 'id' => $row['id']]);
392
        }
393
    }
394
395
    /**
396
     * Run inserted rows to Zoho : local_insert.
397
     *
398
     * @param AbstractZohoDao $zohoDao
399
     */
400
    public function pushInsertedRows(AbstractZohoDao $zohoDao)
401
    {
402
        $this->pushDataToZoho($zohoDao);
403
    }
404
405
    /**
406
     * Run updated rows to Zoho : local_update.
407
     *
408
     * @param AbstractZohoDao $zohoDao
409
     */
410
    public function pushUpdatedRows(AbstractZohoDao $zohoDao)
411
    {
412
        $this->pushDataToZoho($zohoDao, true);
413
    }
414
415
    /**
416
     * Push data from db to Zoho.
417
     *
418
     * @param AbstractZohoDao $zohoDao
419
     */
420
    public function pushToZoho(AbstractZohoDao $zohoDao)
421
    {
422
        $this->logger->info(sprintf('Pushing inserted rows for module %s into Zoho...', $zohoDao->getPluralModuleName()));
423
        $this->pushInsertedRows($zohoDao);
424
        $this->logger->info(sprintf('Pushing updated rows for module %s into Zoho...', $zohoDao->getPluralModuleName()));
425
        $this->pushUpdatedRows($zohoDao);
426
        $this->logger->info(sprintf('Pushing deleted rows for module %s into Zoho...', $zohoDao->getPluralModuleName()));
427
        $this->pushDeletedRows($zohoDao);
428
    }
429
}
430