Completed
Push — development ( 227e3a...98bb7e )
by Andrij
14:37
created

ExchangeBase::insertBatch()   B

Complexity

Conditions 4
Paths 5

Size

Total Lines 22
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 6
Bugs 0 Features 0
Metric Value
cc 4
eloc 12
c 6
b 0
f 0
nc 5
nop 2
dl 0
loc 22
rs 8.9197
1
<?php
2
3
namespace exchange\classes;
4
5
use CI_DB_active_record;
6
use CI_DB_result;
7
use Exception;
8
use MY_Controller;
9
use SimpleXMLElement;
10
use SPropertyValue;
11
use SPropertyValueQuery;
12
13
/**
14
 * Base class for import/export
15
 *
16
 * each class that extends ExchangeBase can
0 ignored issues
show
introduced by
Doc comment long description must start with a capital letter
Loading history...
17
 * request its properties from db and xml
18
 *
19
 * @author kolia
20
 * @property CI_DB_active_record $db
21
 */
22
abstract class ExchangeBase
23
{
0 ignored issues
show
introduced by
Opening brace of a class must be on the same line as the definition
Loading history...
24
25
    /**
26
     * "multisingleton"
27
     * @var array
28
     */
29
    protected static $instances = [];
30
31
    /**
32
     *
33
     * @var type
34
     */
35
    protected $db;
36
37
    /**
38
     *
39
     * @var ExchangeDataLoad
40
     */
41
    protected $dataLoad;
42
43
    /**
44
     *
45
     * @var SimpleXMLElement
46
     */
47
    protected $importData;
48
49
    /**
50
     * Current locale
51
     * @var string
52
     */
53
    protected $locale;
54
55
    /**
56
     *
57
     * @var SimpleXMLElement
58
     */
59
    protected $xml;
60
61
    /**
62
     * Storing results about queries
63
     * @var array
64
     */
65
    public static $stats = [];
66
67
    private function __construct() {
0 ignored issues
show
introduced by
Something seems to be off here. Are you sure you want to declare the constructor as private, and the class as abstract?
Loading history...
68
69
        $this->dataLoad = ExchangeDataLoad::getInstance();
70
        $this->locale = MY_Controller::getCurrentLocale();
71
        $ci = &get_instance();
72
        $this->db = $ci->db;
73
    }
74
75
    private function __clone() {
76
77
    }
78
79
    /**
80
     *
81
     * @return Properties|Products
82
     */
83
    public static function getInstance() {
84
85
        $class = get_called_class();
86
        if (!isset(self::$instances[$class])) {
87
            self::$instances[$class] = new $class;
0 ignored issues
show
Coding Style introduced by
Instantiating objects should always be done with parentheses.

The object instantiation should always have parentheses even if no arguments are passed:

new DateTime; // Bad
new DateTime(); // Good
Loading history...
88
        }
89
        return self::$instances[$class];
90
    }
91
92
    public function __get($name) {
93
94
        return $this->dataLoad->$name;
95
    }
96
97
    /**
98
     * Alias for CI insert_batch
99
     * @param string $tableName
100
     * @param array $data
101
     * @throws Exception
0 ignored issues
show
introduced by
Comment missing or not on the next line for @throws tag in function comment
Loading history...
102
     */
103
    protected function insertBatch($tableName, $data) {
104
105
        if (FALSE == (count($data) > 0)) {
106
            return;
107
        }
108
109
        foreach ($data as $value) {
110
            $this->db->set($value)->insert($tableName);
111
        }
112
113
        $error = $this->db->_error_message();
114
115
        if (!empty($error)) {
116
            throw new Exception("Error on inserting into `{$tableName}`: " . $error);
117
        }
118
        // gathering statistics
119
        ExchangeBase::$stats[] = [
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
120
                                  'query type'    => 'insert',
121
                                  'table name'    => $tableName,
122
                                  'affected rows' => count($data),
123
                                 ];
124
    }
125
126
    /**
127
     * Alias for CI insert_batch
128
     * @param string $tableName
129
     * @param array $data
130
     * @throws Exception
0 ignored issues
show
introduced by
Comment missing or not on the next line for @throws tag in function comment
Loading history...
131
     * @return bool|void
0 ignored issues
show
Documentation introduced by
Consider making the return type a bit more specific; maybe use false|null.

This check looks for the generic type array as a return type and suggests a more specific type. This type is inferred from the actual code.

Loading history...
132
     */
133
    protected function insertPropertiesData($tableName, $data) {
134
135
        if (FALSE == (count($data) > 0)) {
136
            return false;
137
        }
138
139
        foreach ($data as $value) {
140
141
            $property_value = SPropertyValueQuery::create()
142
                ->useSPropertyValueI18nQuery()
143
                ->filterByLocale($value['locale'])
144
                ->filterByValue($value['value'])
145
                ->endUse()
146
                ->findOneByPropertyId($value['property_id']);
147
148
            if (!$property_value) {
149
150
                $property_value = new SPropertyValue();
151
                $property_value->setPropertyId($value['property_id']);
152
                $property_value->setLocale($value['locale']);
153
                $property_value->setValue($value['value']);
154
                $property_value->save();
155
156
            }
157
158
            $this->db->set($value)->insert($tableName);
159
160
            $import_data = [
161
                            'property_id' => $value['property_id'],
162
                            'product_id'  => $value['product_id'],
163
                            'value_id'    => $property_value->getId(),
164
                           ];
165
166
            /** @var CI_DB_result $test */
167
            $test = $this->db->get_where('shop_product_properties_data', $import_data);
168
169
            if ($test->num_rows() > 0) {
170
                return false;
171
            }
172
173
            $this->db->insert('shop_product_properties_data', $import_data);
174
175
        }
176
177
        $error = $this->db->_error_message();
178
179
        if (!empty($error)) {
180
            throw new Exception("Error on inserting into `{$tableName}`: " . $error);
181
        }
182
        // gathering statistics
183
        ExchangeBase::$stats[] = [
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
184
                                  'query type'    => 'insert',
185
                                  'table name'    => $tableName,
186
                                  'affected rows' => count($data),
187
                                 ];
188
    }
189
190
    public function setXml(SimpleXMLElement $xml) {
191
192
        $this->xml = $xml;
193
    }
194
195
    /**
196
     * Alias for CI update_batch
197
     * @param string $tableName
198
     * @param array $data
199
     * @param string $keyToCompare
200
     * @throws \Exception
0 ignored issues
show
introduced by
Comment missing or not on the next line for @throws tag in function comment
Loading history...
201
     */
202
    protected function updateBatch($tableName, array $data, $keyToCompare) {
203
204
        if (FALSE == (count($data) > 0)) {
205
            return;
206
        }
207
208
        if ('shop_product_categories' == $tableName) {
209
            return;
210
        }
211
212
        //        $this->_updateBatchGroup($tableName, $data, $keyToComare); // error when more than 1 language
213
        $this->_updatePerOne($tableName, $data, $keyToCompare);
214
215
        // gathering statistics
216
        ExchangeBase::$stats[] = [
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
217
                                  'query type'    => 'update',
218
                                  'table name'    => $tableName,
219
                                  'affected rows' => count($data),
220
                                 ];
221
    }
222
223
    /**
224
     *
225
     * @param string $tableName
226
     * @param array $data
227
     * @param string $keyToComare
228
     * @throws Exception
0 ignored issues
show
introduced by
Comment missing or not on the next line for @throws tag in function comment
Loading history...
229
     */
230
    public function _updateBatchGroup($tableName, array $data, $keyToComare) {
231
232
        $this->db->update_batch($tableName, $data, $keyToComare);
233
234
        $error = $this->db->_error_message();
235
236
        if (!empty($error)) {
237
            throw new Exception("Error on updating `{$tableName}`: " . $error);
238
        }
239
    }
240
241
    /**
242
     *
243
     * @param string $tableName
244
     * @param array $data
245
     * @param string $keyToCompare
246
     * @throws Exception
0 ignored issues
show
introduced by
Comment missing or not on the next line for @throws tag in function comment
Loading history...
247
     */
248
    public function _updatePerOne($tableName, array $data, $keyToCompare) {
249
250
        foreach ($data as $rowData) {
251
            $this->db->update($tableName, $rowData, [$keyToCompare => $rowData[$keyToCompare]], 1);
252
253
            $error = $this->db->_error_message();
254
            if (empty($error)) {
255
                continue;
256
            }
257
258
            log_message('error', sprintf("DB error: '%s'", $error));
259
260
            if (config_item('update:failOnError') == true) {
261
                throw new Exception("Error on updating `{$tableName}`: " . $error);
262
            }
263
        }
264
    }
265
266
    /**
267
     * Return statistic
268
     * @return array
269
     */
270
    public function getStats() {
271
272
        return $this->stats;
273
    }
274
275
    /**
276
     * Sets the data for import, starts import
277
     * @param SimpleXMLElement $importData
278
     */
279
    public function import(SimpleXMLElement $importData) {
280
281
        if (!count($importData) > 0) {
282
            return;
283
        }
284
        $this->importData = $importData;
285
        $this->import_();
286
        return;
287
    }
288
289
    /**
290
     * Runs the import process
291
     */
292
    abstract protected function import_();
0 ignored issues
show
Documentation introduced by
For interfaces and abstract methods it is generally a good practice to add a @return annotation even if it is just @return void or @return null, so that implementors know what to do in the overridden method.

For interface and abstract methods, it is impossible to infer the return type from the immediate code. In these cases, it is generally advisible to explicitly annotate these methods with a @return doc comment to communicate to implementors of these methods what they are expected to return.

Loading history...
293
294
}