Completed
Pull Request — 2.0 (#7)
by Raphaël
11:08
created

ZohoDatabaseCopier::fetchFromZoho()   D

Complexity

Conditions 12
Paths 180

Size

Total Lines 92
Code Lines 59

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 1
Metric Value
c 4
b 1
f 1
dl 0
loc 92
rs 4.6933
cc 12
eloc 59
nc 180
nop 3

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
10
/**
11
 * This class is in charge of synchronizing one table of your database with Zoho records.
12
 */
13
class ZohoDatabaseCopier
14
{
15
    /**
16
     * @var Connection
17
     */
18
    private $connection;
19
20
    private $prefix;
21
22
    /**
23
     * @var ZohoChangeListener[]
24
     */
25
    private $listeners;
26
27
    /**
28
     * @var LoggerInterface
29
     */
30
    private $logger;
31
32
    /**
33
     * @var LocalChangesTracker
34
     */
35
    private $localChangesTracker;
36
37
    /**
38
     * ZohoDatabaseCopier constructor.
39
     *
40
     * @param Connection           $connection
41
     * @param string               $prefix     Prefix for the table name in DB
42
     * @param ZohoChangeListener[] $listeners  The list of listeners called when a record is inserted or updated.
43
     */
44
    public function __construct(Connection $connection, $prefix = 'zoho_', array $listeners = [], LoggerInterface $logger = null)
45
    {
46
        $this->connection = $connection;
47
        $this->prefix = $prefix;
48
        $this->listeners = $listeners;
49
        if ($logger === null) {
50
            $this->logger = new NullLogger();
51
        } else {
52
            $this->logger = $logger;
53
        }
54
        $this->localChangesTracker = new LocalChangesTracker($connection, $this->logger);
55
    }
56
57
    /**
58
     * @param AbstractZohoDao $dao
59
     * @param bool            $incrementalSync Whether we synchronize only the modified files or everything.
60
     * @param bool            $twoWaysSync
61
     *
62
     * @throws \Doctrine\DBAL\DBALException
63
     * @throws \Doctrine\DBAL\Schema\SchemaException
64
     * @throws \Wabel\Zoho\CRM\Exception\ZohoCRMResponseException
65
     */
66
    public function fetchFromZoho(AbstractZohoDao $dao, $incrementalSync = true, $twoWaysSync = true)
67
    {
68
        $tableName = ZohoDatabaseHelper::getTableName($dao, $this->prefix);
69
70
        if ($incrementalSync) {
71
            $this->logger->info("Copying incremental data for '$tableName'");
72
            /////'SHOW COLUMNS FROM '.$tableName.' LIKE `lastActivityTime`');
73
            // Let's get the last modification date:
74
            $lastActivityTime = $this->connection->fetchColumn('SELECT MAX(lastActivityTime) FROM '.$tableName);
75
            if ($lastActivityTime !== null) {
76
                $lastActivityTime = new \DateTime($lastActivityTime);
77
                $this->logger->info('Last activity time: '.$lastActivityTime->format('c'));
78
                // Let's add one second to the last activity time (otherwise, we are fetching again the last record in DB).
79
                $lastActivityTime->add(new \DateInterval('PT1S'));
80
            }
81
82
            $records = $dao->getRecords(null, null, $lastActivityTime);
83
            $deletedRecordIds = $dao->getDeletedRecordIds($lastActivityTime);
84
        } else {
85
            $this->logger->notice("Copying FULL data for '$tableName'");
86
            $records = $dao->getRecords();
87
            $deletedRecordIds = [];
88
        }
89
        $this->logger->info('Fetched '.count($records).' records');
90
91
        $table = $this->connection->getSchemaManager()->createSchema()->getTable($tableName);
92
93
        $flatFields = ZohoDatabaseHelper::getFlatFields($dao->getFields());
0 ignored issues
show
Bug introduced by
The method getFields() cannot be called from this context as it is declared protected in class Wabel\Zoho\CRM\AbstractZohoDao.

This check looks for access to methods that are not accessible from the current context.

If you need to make a method accessible to another context you can raise its visibility level in the defining class.

Loading history...
94
        $fieldsByName = [];
95
        foreach ($flatFields as $field) {
96
            $fieldsByName[$field['name']] = $field;
97
        }
98
99
        $select = $this->connection->prepare('SELECT * FROM '.$tableName.' WHERE id = :id');
100
101
        $this->connection->beginTransaction();
102
103
        foreach ($records as $record) {
104
            $data = [];
105
            $types = [];
106
            foreach ($table->getColumns() as $column) {
107
                if (in_array($column->getName(), ['id', 'uid'])) {
108
                    continue;
109
                } else {
110
                    $field = $fieldsByName[$column->getName()];
111
                    $getterName = $field['getter'];
112
                    $data[$column->getName()] = $record->$getterName();
113
                    $types[$column->getName()] = $column->getType()->getName();
114
                }
115
            }
116
117
            $select->execute(['id' => $record->getZohoId()]);
118
            $result = $select->fetch(\PDO::FETCH_ASSOC);
119
            if ($result === false) {
120
                $this->logger->debug("Inserting record with ID '".$record->getZohoId()."'.");
121
122
                $data['id'] = $record->getZohoId();
123
                $types['id'] = 'string';
124
125
                $this->connection->insert($tableName, $data, $types);
126
127
                foreach ($this->listeners as $listener) {
128
                    $listener->onInsert($data, $dao);
129
                }
130
            } else {
131
                $this->logger->debug("Updating record with ID '".$record->getZohoId()."'.");
132
                $identifier = ['id' => $record->getZohoId()];
133
                $types['id'] = 'string';
134
135
                $this->connection->update($tableName, $data, $identifier, $types);
136
137
                // Let's add the id for the update trigger
138
                $data['id'] = $record->getZohoId();
139
                foreach ($this->listeners as $listener) {
140
                    $listener->onUpdate($data, $result, $dao);
141
                }
142
            }
143
        }
144
        $sqlStatementUid = 'select uid from '.$this->connection->quoteIdentifier($tableName).' where id = :id';
145
        foreach ($deletedRecordIds as $id) {
146
            $uid = $this->connection->fetchColumn($sqlStatementUid, ['id' => $id]);
147
            $this->connection->delete($tableName, ['id' => $id]);
148
            if ($twoWaysSync) {
149
                // TODO: we could detect if there are changes to be updated to the server and try to warn with a log message
150
                // Also, let's remove the newly created field (because of the trigger) to avoid looping back to Zoho
151
                $this->connection->delete('local_delete', ['table_name' => $tableName, 'id' => $id]);
152
                $this->connection->delete('local_update', ['table_name' => $tableName, 'uid' => $uid]);
153
            }
154
        }
155
156
        $this->connection->commit();
157
    }
158
}
159