Completed
Push — master ( 117aa5...9fc286 )
by diego
04:15
created

InsertUpdateTable::insertRecord()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 16
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 16
ccs 0
cts 11
cp 0
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 10
nc 2
nop 1
crap 6
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
 *   filter:
25
 *     - password
26
 *   mapping:
27
 *     0: username
28
 *     1: password
29
 *     2: usergroup
30
 *     3: name
31
 *     4: first_name
32
 *     5: address
33
 *     6: telephone
34
 *     7: email
35
 *     8: zip
36
 *     9: city
37
 *     10: company
38
 *
39
 * Example CSV:
40
 *
41
 * username;password;usergroup;name;first_name;address;telephone;email;zip;city;company
42
 * EduardFekete;PW123;3;Fekete;Eduard; Example 21; +049123456789;[email protected];91550;Feuchtwangen;MB Connect Line GmbH
43
 * HansVader;PW1234;3;Vader;Hans; Example 22; +049123456710;[email protected];99900;Universe;Hollywood Studios
44
 *
45
 * ------------------------------------------------------------------------------------------------
46
 *
47
 *   exclude_from_update:    the elements specified in this array, are never being updated
48
 *
49
 *   salt_password:          if set to 1 then passwords are being salted before they are stored in the database
50
 *
51
 * ------------------------------------------------------------------------------------------------
52
 * @author Eduard Fekete
53
 */
54
class InsertUpdateTable extends DbRecord implements TargetInterface
55
{
56
    /**
57
     * @var int
58
     */
59
    protected $identifierField;
60
61
    /**
62
     * @param Strategy $strategy
63
     */
64
    public function start(Strategy $strategy)
65
    {
66
        parent::start($strategy);
67
        if (!isset($this->getConfiguration()['identifier'])) {
68
            throw new \RuntimeException('Identifier field is missing!');
69
        }
70
        $identifier = $this->getConfiguration()['identifier'];
71
        $identifierField = array_search($identifier, $this->getConfiguration()['mapping']);
72
        if ($identifierField === false) {
73
            throw new \RuntimeException('Identifier field not found in mapping.');
74
        }
75
        $this->identifierField = $identifierField;
76
    }
77
78
    /**
79
     * Process every entry in the .csv
80
     *
81
     * @param array $entry
82
     *
83
     * @return int|void
84
     */
85
    public function processEntry(array $entry)
86
    {
87
        $record_exists = false;
88
        $entry_identifier = $entry[$this->identifierField];
89
        $records = $this->getRecords("*");
90
        $fieldName = $this->getConfiguration()['mapping'][$this->identifierField];
91
92
        foreach ($records as $record) {
0 ignored issues
show
Bug introduced by
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...
93
            if ($record['deleted'] == 0) {
94
                if ($record[$fieldName] == $entry_identifier) {
95
                    $record_exists = true;
96
                    break;
97
                }
98
            } else {
99
                continue;
100
            }
101
        }
102
103
        if ($record_exists) {
104
            $this->updateRecord($entry);
105
            return TargetInterface::RESULT_UPDATE;
106
        }
107
108
        $this->insertRecord($entry);
109
        return TargetInterface::RESULT_INSERT;
110
    }
111
112
    /**
113
     *
114
     * Fetch all records from the target table, where the PID equals the PID specified
115
     * in the target section of the strategy
116
     *
117
     * @param $selectFields
118
     * @return array
119
     */
120
    protected function getRecords($selectFields)
121
    {
122
        static $records = [];
123
        if ($records) {
0 ignored issues
show
Bug Best Practice introduced by
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...
124
            return $records;
125
        }
126
127
        $fromTable = $this->getConfiguration()['target_table'];
128
        $whereStatement = "pid = '" . $this->getConfiguration()['pid'] . "'";
129
130
        $records = Utility::getDatabaseConnection()->exec_SELECTgetRows(
131
            $selectFields,
132
            $fromTable,
133
            $whereStatement
134
        );
135
136
        return $records;
137
    }
138
139
    /**
140
     * Insert record into the target table which you have specified in the target section of the strategy
141
     *
142
     * @param array $entry
143
     *
144
     * @return void
145
     */
146
    protected function insertRecord(array $entry)
147
    {
148
        $field_values = [];
149
        $into_table = $this->getConfiguration()['target_table'];
150
151
        foreach ($this->getConfiguration()["mapping"] as $key => $value) {
152
            $field_values[$value] = $entry[$key];
153
        }
154
155
        $field_values['pid'] = $this->getConfiguration()['pid'];
156
        $time = time();
157
        $field_values['tstamp'] = $time;
158
        $field_values['crdate'] = $time;
159
160
        Utility::getDatabaseConnection()->exec_INSERTquery($into_table, $field_values);
161
    }
162
163
    /**
164
     * Update a record in the target table which you have specified in the
165
     * target section of the strategy (don't update the password)
166
     *
167
     * @param array $entry
168
     *
169
     * @return void
170
     */
171
    protected function updateRecord(array $entry)
172
    {
173
        $into_table = $this->getConfiguration()['target_table'];
174
        $fieldName = $this->getConfiguration()['mapping'][$this->identifierField];
175
        $whereStatement = "pid = '" . $this->getConfiguration()['pid'] . "' AND " . $fieldName . " = '" . $entry[$this->identifierField] . "'";
176
177
        $tmp_arr = [];
178
179
        foreach ($this->getConfiguration()["mapping"] as $key => $value) {
180
            $tmp_arr[$value] = $entry[$key];
181
        }
182
183
        $field_values = $this->duplicateArray($tmp_arr, $this->getConfiguration()['exclude_from_update']);
184
        $field_values['tstamp'] = time();
185
186
        Utility::getDatabaseConnection()->exec_UPDATEquery($into_table, $whereStatement, $field_values);
187
    }
188
189
    /**
190
     * This function creates a duplicate of a associative array and optionally removes
191
     * any entries which are also elements of a second array
192
     *
193
     * @param array $arr
194
     * @param array $exclude_arr
195
     *
196
     * @return array
197
     */
198
    protected function duplicateArray(array $arr, array $exclude_arr = null)
199
    {
200
        if (!is_array($exclude_arr)) {
201
            return $arr;
202
        }
203
204
        foreach ($arr as $key => $_) {
205
            if (in_array($key, $exclude_arr)) {
206
                unset($arr[$key]);
207
            }
208
        }
209
210
        return $arr;
211
    }
212
213
    /**
214
     *
215
     */
216
    public function end()
217
    {
218
        parent::end();
219
    }
220
}
221