Completed
Push — master ( 36506d...dd98a7 )
by diego
04:15
created

InsertUpdateTable::duplicateArray()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 14
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
dl 0
loc 14
ccs 0
cts 7
cp 0
rs 9.2
c 0
b 0
f 0
cc 4
eloc 7
nc 4
nop 2
crap 20
1
<?php
2
namespace HDNET\Importr\Service\Targets;
3
4
use HDNET\Importr\Domain\Model\Strategy;
5
use TYPO3\CMS\Extbase\DomainObject\AbstractEntity;
6
use HDNET\Importr\Utility;
7
8
/**
9
 * Imports records from a .CSV file into the target table which you
10
 * can specify on the target section in your strategy.
11
 * If a record does not exist in the table, it will be inserted,
12
 * otherwise it will be just updated. No duplicates are created.
13
 *
14
 * complete example (strategy target):
15
 *
16
 * HDNET\Importr\Service\Targets\InsertUpdateTable:
17
 *   target_table: fe_users
18
 *   exclude_from_update:
19
 *     0: password
20
 *     1: first_name
21
 *     2: zip
22
 *   pid: 324
23
 *   identifier: username
24
 *   mapping:
25
 *     0: username
26
 *     1: password
27
 *     2: usergroup
28
 *     3: name
29
 *     4: first_name
30
 *     5: address
31
 *     6: telephone
32
 *     7: email
33
 *     8: zip
34
 *     9: city
35
 *     10: company
36
 *
37
 * Example CSV:
38
 *
39
 * username;password;usergroup;name;first_name;address;telephone;email;zip;city;company
40
 * EduardFekete;PW123;3;Fekete;Eduard; Example 21; +049123456789;[email protected];91550;Feuchtwangen;MB Connect Line GmbH
41
 * HansVader;PW1234;3;Vader;Hans; Example 22; +049123456710;[email protected];99900;Universe;Hollywood Studios
42
 *
43
 * ------------------------------------------------------------------------------------------------
44
 *
45
 *   exclude_from_update:    the elements specified in this array, are never being updated
46
 *
47
 * ------------------------------------------------------------------------------------------------
48
 * @author Eduard Fekete
49
 */
50
class InsertUpdateTable extends DbRecord implements TargetInterface
51
{
52
    /**
53
     * @var int
54
     */
55
    protected $identifierField;
56
57
    /**
58
     * @param Strategy $strategy
59
     */
60
    public function start(Strategy $strategy)
61
    {
62
        parent::start($strategy);
63
        if (!isset($this->getConfiguration()['identifier'])) {
64
            throw new \RuntimeException('Identifier field is missing!');
65
        }
66
        $identifier = $this->getConfiguration()['identifier'];
67
        $identifierField = array_search($identifier, $this->getConfiguration()['mapping']);
68
        if ($identifierField === false) {
69
            throw new \RuntimeException('Identifier field not found in mapping.');
70
        }
71
        $this->identifierField = $identifierField;
72
    }
73
74
    /**
75
     * Process every entry in the .csv
76
     *
77
     * @param array $entry
78
     *
79
     * @return int|void
80
     */
81
    public function processEntry(array $entry)
82
    {
83
        $record_exists = false;
84
        $entry_identifier = $entry[$this->identifierField];
85
        $records = $this->getRecords("*");
86
        $fieldName = $this->getConfiguration()['mapping'][$this->identifierField];
87
88
        foreach ($records as $record) {
0 ignored issues
show
Bug introduced by Tim Spiekerkötter
The expression $records of type array|null is not guaranteed to be traversable. How about adding an additional type check?

There are different options of fixing this problem.

  1. If you want to be on the safe side, you can add an additional type-check:

    $collection = json_decode($data, true);
    if ( ! is_array($collection)) {
        throw new \RuntimeException('$collection must be an array.');
    }
    
    foreach ($collection as $item) { /** ... */ }
    
  2. If you are sure that the expression is traversable, you might want to add a doc comment cast to improve IDE auto-completion and static analysis:

    /** @var array $collection */
    $collection = json_decode($data, true);
    
    foreach ($collection as $item) { /** .. */ }
    
  3. Mark the issue as a false-positive: Just hover the remove button, in the top-right corner of this issue for more options.

Loading history...
89
            if ($record['deleted'] == 0) {
90
                if ($record[$fieldName] == $entry_identifier) {
91
                    $record_exists = true;
92
                    break;
93
                }
94
            } else {
95
                continue;
96
            }
97
        }
98
99
        if ($record_exists) {
100
            $this->updateRecord($entry);
101
            return TargetInterface::RESULT_UPDATE;
102
        }
103
104
        $this->insertRecord($entry);
105
        return TargetInterface::RESULT_INSERT;
106
    }
107
108
    /**
109
     *
110
     * Fetch all records from the target table, where the PID equals the PID specified
111
     * in the target section of the strategy
112
     *
113
     * @param $selectFields
114
     * @return array
115
     */
116
    protected function getRecords($selectFields)
117
    {
118
        static $records = [];
119
        if ($records) {
0 ignored issues
show
Bug Best Practice introduced by Tim Spiekerkötter
The expression $records of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
120
            return $records;
121
        }
122
123
        $fromTable = $this->getConfiguration()['target_table'];
124
        $whereStatement = "pid = '" . $this->getConfiguration()['pid'] . "'";
125
126
        $records = Utility::getDatabaseConnection()->exec_SELECTgetRows(
127
            $selectFields,
128
            $fromTable,
129
            $whereStatement
130
        );
131
132
        return $records;
133
    }
134
135
    /**
136
     * Insert record into the target table which you have specified in the target section of the strategy
137
     *
138
     * @param array $entry
139
     *
140
     * @return void
141
     */
142
    protected function insertRecord(array $entry)
143
    {
144
        $field_values = [];
145
        $into_table = $this->getConfiguration()['target_table'];
146
147
        foreach ($this->getConfiguration()["mapping"] as $key => $value) {
148
            $field_values[$value] = $entry[$key];
149
        }
150
151
        $field_values['pid'] = $this->getConfiguration()['pid'];
152
        $time = time();
153
        $field_values['tstamp'] = $time;
154
        $field_values['crdate'] = $time;
155
156
        Utility::getDatabaseConnection()->exec_INSERTquery($into_table, $field_values);
157
    }
158
159
    /**
160
     * Update a record in the target table which you have specified in the
161
     * target section of the strategy (don't update the password)
162
     *
163
     * @param array $entry
164
     *
165
     * @return void
166
     */
167
    protected function updateRecord(array $entry)
168
    {
169
        $into_table = $this->getConfiguration()['target_table'];
170
        $fieldName = $this->getConfiguration()['mapping'][$this->identifierField];
171
        $whereStatement = "pid = '" . $this->getConfiguration()['pid'] . "' AND '" . $fieldName . "' = '" . $entry[$this->identifierField] . "'";
172
173
        $tmp_arr = [];
174
175
        foreach ($this->getConfiguration()["mapping"] as $key => $value) {
176
            $tmp_arr[$value] = $entry[$key];
177
        }
178
179
        $field_values = $this->duplicateArray($tmp_arr, $this->getConfiguration()['exclude_from_update']);
180
        $field_values['tstamp'] = time();
181
182
        Utility::getDatabaseConnection()->exec_UPDATEquery($into_table, $whereStatement, $field_values);
183
    }
184
185
    /**
186
     * This function creates a duplicate of a associative array and optionally removes
187
     * any entries which are also elements of a second array
188
     *
189
     * @param array $arr
190
     * @param array $exclude_arr
191
     *
192
     * @return array
193
     */
194
    protected function duplicateArray(array $arr, array $exclude_arr = null)
195
    {
196
        if (!is_array($exclude_arr)) {
197
            return $arr;
198
        }
199
200
        foreach ($arr as $key => $_) {
201
            if (in_array($key, $exclude_arr)) {
202
                unset($arr[$key]);
203
            }
204
        }
205
206
        return $arr;
207
    }
208
209
    /**
210
     *
211
     */
212
    public function end()
213
    {
214
        parent::end();
215
    }
216
}
217