Completed
Push — 2.0 ( 94a944...924b75 )
by Raphaël
08:39
created

ZohoDatabaseModelSync   B

Complexity

Total Complexity 44

Size/Duplication

Total Lines 226
Duplicated Lines 4.87 %

Coupling/Cohesion

Components 1
Dependencies 9

Importance

Changes 2
Bugs 0 Features 0
Metric Value
wmc 44
lcom 1
cbo 9
dl 11
loc 226
rs 8.3396
c 2
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 11 11 2
A setLogger() 0 4 1
F synchronizeDbModel() 0 110 31
C synchronizeUserDbModel() 0 59 10

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like ZohoDatabaseModelSync often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use ZohoDatabaseModelSync, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
namespace Wabel\Zoho\CRM\Copy;
4
5
use Doctrine\DBAL\Connection;
6
use Doctrine\DBAL\Schema\Schema;
7
use Psr\Log\LoggerInterface;
8
use Psr\Log\NullLogger;
9
use Wabel\Zoho\CRM\AbstractZohoDao;
10
use Wabel\Zoho\CRM\Request\Response;
11
12
/**
13
 * This class is in charge of synchronizing one table MODEL with Zoho.
14
 */
15
class ZohoDatabaseModelSync
16
{
17
    /**
18
     * @var Connection
19
     */
20
    private $connection;
21
22
    private $prefix;
23
24
    /**
25
     * @var LoggerInterface
26
     */
27
    private $logger;
28
29
    /**
30
     * @var LocalChangesTracker
31
     */
32
    private $localChangesTracker;
33
34
    /**
35
     * ZohoDatabaseCopier constructor.
36
     *
37
     * @param Connection $connection
38
     * @param string     $prefix     Prefix for the table name in DB
39
     */
40 View Code Duplication
    public function __construct(Connection $connection, $prefix = 'zoho_', LoggerInterface $logger = null)
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...
41
    {
42
        $this->connection = $connection;
43
        $this->prefix = $prefix;
44
        if ($logger === null) {
45
            $this->logger = new NullLogger();
46
        } else {
47
            $this->logger = $logger;
48
        }
49
        $this->localChangesTracker = new LocalChangesTracker($connection, $this->logger);
50
    }
51
52
    /**
53
     * @param LoggerInterface $logger
54
     */
55
    public function setLogger(LoggerInterface $logger)
56
    {
57
        $this->logger = $logger;
58
    }
59
60
    /**
61
     * Synchronizes the DB model with Zoho.
62
     *
63
     * @param AbstractZohoDao $dao
64
     * @param bool            $twoWaysSync
65
     * @param bool            $skipCreateTrigger
66
     *
67
     * @throws \Doctrine\DBAL\DBALException
68
     * @throws \Doctrine\DBAL\Schema\SchemaException
69
     */
70
    public function synchronizeDbModel(AbstractZohoDao $dao, $twoWaysSync, $skipCreateTrigger = false)
71
    {
72
        if ($twoWaysSync === true) {
73
            $this->localChangesTracker->createTrackingTables();
74
        }
75
76
        $tableName = ZohoDatabaseHelper::getTableName($dao, $this->prefix);
77
        $this->logger->info('Synchronizing DB Model for '.$tableName);
78
79
        $schema = new Schema();
80
        $table = $schema->createTable($tableName);
81
82
        $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...
83
        $table->addColumn('uid', 'integer', ['autoincrement' => true]);
84
        $table->addColumn('id', 'string', ['length' => 100,'notnull'=>false]);
85
        $table->addUniqueIndex(['id']);
86
        $table->setPrimaryKey(['uid']);
87
88
        foreach ($flatFields as $field) {
89
            $columnName = $field['name'];
90
91
            $length = null;
92
            $index = false;
93
94
            // Note: full list of types available here: https://www.zoho.com/crm/help/customization/custom-fields.html
95
            switch ($field['type']) {
96
                case 'Lookup ID':
97
                case 'Lookup':
98
                    $type = 'string';
99
                    $length = 100;
100
                    $index = true;
101
                    break;
102
                case 'OwnerLookup':
103
                    $type = 'string';
104
                    $index = true;
105
                    $length = 25;
106
                    break;
107
                case 'Formula':
108
                    // Note: a Formula can return any type, but we have no way to know which type it returns...
109
                    $type = 'string';
110
                    $length = 100;
111
                    break;
112
                case 'DateTime':
113
                    $type = 'datetime';
114
                    break;
115
                case 'Date':
116
                    $type = 'date';
117
                    break;
118
                case 'DateTime':
119
                    $type = 'datetime';
120
                    break;
121
                case 'Boolean':
122
                    $type = 'boolean';
123
                    break;
124
                case 'TextArea':
125
                    $type = 'text';
126
                    break;
127
                case 'BigInt':
128
                    $type = 'bigint';
129
                    break;
130
                case 'Phone':
131
                case 'Auto Number':
132
                case 'Text':
133
                case 'URL':
134
                case 'Email':
135
                case 'Website':
136
                case 'Pick List':
137
                case 'Multiselect Pick List':
138
                    // $field['maxlength'] is not enough
0 ignored issues
show
Unused Code Comprehensibility introduced by
37% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
139
                    $type = 'text';
140
                    break;
141
                case 'Double':
142
                case 'Percent':
143
                    $type = 'float';
144
                    break;
145
                case 'Integer':
146
                    $type = 'integer';
147
                    break;
148
                case 'Currency':
149
                case 'Decimal':
150
                    $type = 'decimal';
151
                    break;
152
                default:
153
                    throw new \RuntimeException('Unknown type "'.$field['type'].'"');
154
            }
155
156
            $options = [];
157
158
            if ($length) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $length of type integer|null is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
159
                $options['length'] = $length;
160
            }
161
162
            //$options['notnull'] = $field['req'];
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
163
            $options['notnull'] = false;
164
165
            $table->addColumn($columnName, $type, $options);
166
167
            if ($index) {
168
                $table->addIndex([$columnName]);
169
            }
170
        }
171
172
        $dbalTableDiffService = new DbalTableDiffService($this->connection, $this->logger);
173
        $hasChanges = $dbalTableDiffService->createOrUpdateTable($table);
174
        if ($twoWaysSync && ($hasChanges || !$skipCreateTrigger)) {
175
            $this->localChangesTracker->createInsertTrigger($table);
176
            $this->localChangesTracker->createDeleteTrigger($table);
177
            $this->localChangesTracker->createUpdateTrigger($table);
178
        }
179
    }
180
181
    public function synchronizeUserDbModel(Response $users)
182
    {
183
        $tableName = 'users';
184
185
        $schema = new Schema();
186
        $table = $schema->createTable($tableName);
187
188
        $flatFields = $users->getUserFields();
189
        $table->addColumn('uid', 'integer', ['autoincrement' => true]);
190
        $table->addColumn('id', 'string', ['length' => 100,'notnull'=>false]);
191
        $table->addUniqueIndex(['id']);
192
        $table->setPrimaryKey(['uid']);
193
        foreach ($flatFields as $field) {
194
            if(in_array($field, ['id'])){
195
                continue;
196
            }
197
            $columnName = $field;
198
            $length = null;
199
            $index = false;
200
            switch ($field) {
201
                case 'zuid':
202
                    $type = 'string';
203
                    $length = 100;
204
                    $index = true;
205
                    break;
206
                case 'name':
207
                case 'email':
208
                    $type = 'string';
209
                    $length = 255;
210
                    $index = true;
211
                    break;
212
                case 'phone':
213
                case 'website':
214
                    $type = 'text';
215
                    break;
216
                default:
217
                    $type = 'string';
218
                    $length = 100;
219
            }
220
221
            $options = [];
222
223
            if ($length) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $length of type null|integer is loosely compared to true; this is ambiguous if the integer can be zero. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
224
                $options['length'] = $length;
225
            }
226
227
            //$options['notnull'] = $field['req'];
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
228
            $options['notnull'] = false;
229
230
            $table->addColumn($columnName, $type, $options);
231
232
            if ($index) {
233
                $table->addIndex([$columnName]);
234
            }
235
        }
236
237
        $dbalTableDiffService = new DbalTableDiffService($this->connection, $this->logger);
238
        $dbalTableDiffService->createOrUpdateTable($table);
239
    }
240
}
241