1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* TechDivision\Import\Actions\Processors\AbstractBaseProcessor |
5
|
|
|
* |
6
|
|
|
* NOTICE OF LICENSE |
7
|
|
|
* |
8
|
|
|
* This source file is subject to the Open Software License (OSL 3.0) |
9
|
|
|
* that is available through the world-wide-web at this URL: |
10
|
|
|
* http://opensource.org/licenses/osl-3.0.php |
11
|
|
|
* |
12
|
|
|
* PHP version 5 |
13
|
|
|
* |
14
|
|
|
* @author Tim Wagner <[email protected]> |
15
|
|
|
* @copyright 2016 TechDivision GmbH <[email protected]> |
16
|
|
|
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) |
17
|
|
|
* @link https://github.com/techdivision/import |
18
|
|
|
* @link http://www.techdivision.com |
19
|
|
|
*/ |
20
|
|
|
|
21
|
|
|
namespace TechDivision\Import\Actions\Processors; |
22
|
|
|
|
23
|
|
|
use TechDivision\Import\Utils\EntityStatus; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* An abstract processor implementation provide basic CRUD functionality. |
27
|
|
|
* |
28
|
|
|
* @author Tim Wagner <[email protected]> |
29
|
|
|
* @copyright 2016 TechDivision GmbH <[email protected]> |
30
|
|
|
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) |
31
|
|
|
* @link https://github.com/techdivision/import |
32
|
|
|
* @link http://www.techdivision.com |
33
|
|
|
*/ |
34
|
|
|
abstract class AbstractBaseProcessor extends AbstractProcessor |
35
|
|
|
{ |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* The array with the statements to be prepared. |
39
|
|
|
* |
40
|
|
|
* @var array |
41
|
|
|
*/ |
42
|
|
|
protected $statements = array(); |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* The array with the prepared statements. |
46
|
|
|
* |
47
|
|
|
* @var array |
48
|
|
|
*/ |
49
|
|
|
protected $preparedStatements = array(); |
50
|
|
|
|
51
|
|
|
/** |
52
|
|
|
* The default statement name. |
53
|
|
|
* |
54
|
|
|
* @var string |
55
|
|
|
*/ |
56
|
|
|
protected $defaultStatementName; |
57
|
|
|
|
58
|
|
|
/** |
59
|
|
|
* Return's the array with the SQL statements that has to be prepared. |
60
|
|
|
* |
61
|
|
|
* @return array The SQL statements to be prepared |
62
|
|
|
*/ |
63
|
|
|
protected function getStatements() |
64
|
|
|
{ |
65
|
|
|
return $this->statements; |
66
|
|
|
} |
67
|
|
|
|
68
|
|
|
/** |
69
|
|
|
* Add's the prepared statement. |
70
|
|
|
* |
71
|
|
|
* @param string $name The unique name of the prepared statement |
72
|
|
|
* @param \PDOStatement $preparedStatement The prepared statement |
73
|
|
|
* |
74
|
|
|
* @return void |
75
|
|
|
*/ |
76
|
|
|
protected function addPreparedStatement($name, \PDOStatement $preparedStatement) |
77
|
|
|
{ |
78
|
|
|
$this->preparedStatements[$name] = $preparedStatement; |
79
|
|
|
} |
80
|
|
|
|
81
|
|
|
/** |
82
|
|
|
* Return's the prepared statement with the passed name or the default one. |
83
|
|
|
* |
84
|
|
|
* @param string|null $name The name of the prepared statement to return |
85
|
|
|
* @param string|null $defaultName The name of the default prepared statement |
86
|
|
|
* |
87
|
|
|
* @return \PDOStatement The prepared statement |
88
|
|
|
*/ |
89
|
|
|
protected function getPreparedStatement($name = null, $defaultName = null) |
90
|
|
|
{ |
91
|
|
|
|
92
|
|
|
// try to load the prepared statement, or use the default one |
93
|
|
|
if (isset($this->preparedStatements[$name])) { |
94
|
|
|
return $this->preparedStatements[$name]; |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
// return the default prepared statement |
98
|
|
|
return $this->preparedStatements[$defaultName]; |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* Qeuery whether or not the prepared statement is available or not. |
103
|
|
|
* |
104
|
|
|
* @param string $name The nqme of the prepared statement |
105
|
|
|
* |
106
|
|
|
* @return boolean TRUE if the prepared statement is available, else FALSE |
107
|
|
|
*/ |
108
|
|
|
protected function hasPreparedStatement($name) |
109
|
|
|
{ |
110
|
|
|
return isset($this->preparedStatements[$name]); |
111
|
|
|
} |
112
|
|
|
|
113
|
|
|
/** |
114
|
|
|
* The array with the prepared statements. |
115
|
|
|
* |
116
|
|
|
* @return array The prepared statments |
117
|
|
|
*/ |
118
|
|
|
protected function getPreparedStatements() |
119
|
|
|
{ |
120
|
|
|
return $this->preparedStatements; |
121
|
|
|
} |
122
|
|
|
|
123
|
|
|
/** |
124
|
|
|
* Prepare's and return's the passed row by removing the |
125
|
|
|
* entity status. |
126
|
|
|
* |
127
|
|
|
* @param array $row The row to prepare |
128
|
|
|
* |
129
|
|
|
* @return array The prepared row |
130
|
|
|
*/ |
131
|
|
|
protected function prepareRow(array $row) |
132
|
|
|
{ |
133
|
|
|
|
134
|
|
|
// remove the entity status |
135
|
|
|
unset($row[EntityStatus::MEMBER_NAME]); |
136
|
|
|
|
137
|
|
|
// return the prepared row |
138
|
|
|
return $row; |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
/** |
142
|
|
|
* Return's the name of the processor's default statement. |
143
|
|
|
* |
144
|
|
|
* @return string The statement name |
145
|
|
|
*/ |
146
|
|
|
public function getDefaultStatementName() |
147
|
|
|
{ |
148
|
|
|
return $this->defaultStatementName; |
149
|
|
|
} |
150
|
|
|
|
151
|
|
|
/** |
152
|
|
|
* Implements the CRUD functionality the processor is responsible for, |
153
|
|
|
* can be one of CREATE, READ, UPDATE or DELETE a entity. |
154
|
|
|
* |
155
|
|
|
* @param array $row The row to persist |
156
|
|
|
* @param string|null $name The name of the prepared statement that has to be executed |
157
|
|
|
* @param string|null $primaryKeyMemberName The primary key member name of the entity to use |
158
|
|
|
* |
159
|
|
|
* @return void |
160
|
|
|
*/ |
161
|
|
|
public function execute($row, $name = null, $primaryKeyMemberName = null) |
162
|
|
|
{ |
163
|
|
|
try { |
164
|
|
|
// finally execute the prepared statement |
165
|
|
|
$this->getPreparedStatement($name, $this->getDefaultStatementName())->execute($this->prepareRow($row)); |
166
|
|
|
} catch (\PDOException $pdoe) { |
167
|
|
|
// initialize the SQL statement with the placeholders |
168
|
|
|
$sql = $this->getPreparedStatement($name, $this->getDefaultStatementName())->queryString; |
169
|
|
|
|
170
|
|
|
// replace the placeholders with the values |
171
|
|
|
foreach ($row as $key => $value) { |
172
|
|
|
$sql = str_replace(sprintf(':%s', $key), $value, $sql); |
173
|
|
|
} |
174
|
|
|
|
175
|
|
|
// prepare the error message itself |
176
|
|
|
$message = sprintf('%s when executing SQL "%s"', $pdoe->getMessage(), preg_replace('/\r\n\s\s+/', ' ', $sql)); |
177
|
|
|
|
178
|
|
|
// re-throw the exception with a more detailed error message |
179
|
|
|
throw new \PDOException($message, null, $pdoe); |
180
|
|
|
} |
181
|
|
|
} |
182
|
|
|
|
183
|
|
|
/** |
184
|
|
|
* Initializes the proceessor with the prepared statements. |
185
|
|
|
* |
186
|
|
|
* @return void |
187
|
|
|
*/ |
188
|
|
|
public function init() |
189
|
|
|
{ |
190
|
|
|
|
191
|
|
|
// load the statements |
192
|
|
|
$statements = $this->getStatements(); |
193
|
|
|
|
194
|
|
|
// initialize the default statement name |
195
|
|
|
$this->defaultStatementName = $this->firstKey($statements); |
|
|
|
|
196
|
|
|
|
197
|
|
|
foreach ($statements as $name => $statement) { |
198
|
|
|
$this->addPreparedStatement($name, $this->getConnection()->prepare($statement)); |
199
|
|
|
} |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* Returns the first key of the passed array. |
204
|
|
|
* |
205
|
|
|
* This method has been used instead of the PHP function array_key_first, because |
206
|
|
|
* this function will be available with PHP >= 7.3.0. |
207
|
|
|
* |
208
|
|
|
* @param array $array The array to return the first key for |
209
|
|
|
* |
210
|
|
|
* @return mixed|NULL The first key or NULL |
211
|
|
|
* @link https://www.php.net/array_key_first |
212
|
|
|
*/ |
213
|
|
|
private function firstKey(array $array) |
214
|
|
|
{ |
215
|
|
|
|
216
|
|
|
// load the array keys |
217
|
|
|
$keys = array_keys($array); |
218
|
|
|
|
219
|
|
|
// try to load and return the first key |
220
|
|
|
foreach($keys as $key) { |
221
|
|
|
return $key; |
222
|
|
|
} |
223
|
|
|
|
224
|
|
|
// return NULL otherwise |
225
|
|
|
return null; |
226
|
|
|
} |
227
|
|
|
} |
228
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.