These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | View Code Duplication | class DatabaseConnection |
|
0 ignored issues
–
show
|
|||
4 | { |
||
5 | /** |
||
6 | * [$instance description] |
||
7 | * @var [type] |
||
8 | */ |
||
9 | private static $instance; |
||
10 | |||
11 | /** |
||
12 | * [$databaseConnection description] |
||
13 | * @var [type] |
||
14 | */ |
||
15 | public $databaseConnection; |
||
16 | |||
17 | /** |
||
18 | * The default PDO connection options. |
||
19 | * |
||
20 | * @var array |
||
21 | */ |
||
22 | protected $options = [ |
||
23 | PDO::ATTR_CASE => PDO::CASE_NATURAL, |
||
24 | PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, |
||
25 | PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL, |
||
26 | PDO::ATTR_STRINGIFY_FETCHES => false, |
||
27 | PDO::ATTR_EMULATE_PREPARES => false, |
||
28 | ]; |
||
29 | |||
30 | /** |
||
31 | * Singleton Class: |
||
32 | * Constructor reads database config file and creates connection. |
||
33 | */ |
||
34 | private function __construct(DatabaseConnectionStringFactoryInterface $dbConnStringFactory) |
||
35 | { |
||
36 | //Read config file |
||
37 | $this->config = parse_ini_file('config.ini'); |
||
0 ignored issues
–
show
The property
config does not exist. Did you maybe forget to declare it?
In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code: class MyClass { }
$x = new MyClass();
$x->foo = true;
Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion: class MyClass {
public $foo;
}
$x = new MyClass();
$x->foo = true;
![]() |
|||
38 | $dsn = $dbConnStringFactory->createDatabaseSourceString($this->config); |
||
39 | $this->databaseConnection = $this->createConnection($dsn, $this->options); |
||
40 | } |
||
41 | |||
42 | public static function getInstance() |
||
43 | { |
||
44 | if (self::$instance === null) { |
||
45 | self::$instance = new self(new DatabaseConnectionStringFactory); |
||
46 | } |
||
47 | return self::$instance; |
||
48 | } |
||
49 | |||
50 | |||
51 | /** |
||
52 | * Create a new PDO connection. |
||
53 | * |
||
54 | * @param string $dsn |
||
55 | * @param array $config |
||
56 | * @return \PDO |
||
57 | */ |
||
58 | public function createConnection($dsn, array $config) |
||
0 ignored issues
–
show
|
|||
59 | { |
||
60 | $username = $this->config['USERNAME']; |
||
61 | |||
62 | $password = $this->config['PASSWORD']; |
||
63 | |||
64 | |||
65 | try { |
||
66 | $pdo = new PDO($dsn, $username, $password, $this->options); |
||
67 | } catch (Exception $e) { |
||
68 | $pdo = $this->tryAgainIfCausedByLostConnection( |
||
69 | $e, $dsn, $username, $password, $options |
||
0 ignored issues
–
show
|
|||
70 | ); |
||
71 | } |
||
72 | |||
73 | return $pdo; |
||
74 | } |
||
75 | |||
76 | /** |
||
77 | * Get the default PDO connection options. |
||
78 | * |
||
79 | * @return array |
||
80 | */ |
||
81 | public function getDefaultOptions() |
||
82 | { |
||
83 | return $this->options; |
||
84 | } |
||
85 | |||
86 | /** |
||
87 | * Set the default PDO connection options. |
||
88 | * |
||
89 | * @param array $options |
||
90 | * @return void |
||
91 | */ |
||
92 | public function setDefaultOptions(array $options) |
||
93 | { |
||
94 | $this->options = $options; |
||
95 | } |
||
96 | |||
97 | /** |
||
98 | * Handle a exception that occurred during connect execution. |
||
99 | * |
||
100 | * @param \Exception $e |
||
101 | * @param string $dsn |
||
102 | * @param string $username |
||
103 | * @param string $password |
||
104 | * @param array $options |
||
105 | * @return \PDO |
||
106 | * |
||
107 | * @throws \Exception |
||
108 | */ |
||
109 | protected function tryAgainIfCausedByLostConnection(Exception $e, $dsn, $username, $password, $options) |
||
110 | { |
||
111 | if ($this->causedByLostConnection($e)) { |
||
112 | return new PDO($dsn, $username, $password, $options); |
||
113 | } |
||
114 | |||
115 | throw $e; |
||
116 | } |
||
117 | |||
118 | /** |
||
119 | * Determine if the given exception was caused by a lost connection. |
||
120 | * |
||
121 | * @param \Exception $e |
||
122 | * @return bool |
||
123 | */ |
||
124 | protected function causedByLostConnection(Exception $e) |
||
125 | { |
||
126 | $message = $e->getMessage(); |
||
127 | |||
128 | return Helpers::contains($message, [ |
||
129 | 'server has gone away', |
||
130 | 'no connection to the server', |
||
131 | 'Lost connection', |
||
132 | 'is dead or not enabled', |
||
133 | 'Error while sending', |
||
134 | 'decryption failed or bad record mac', |
||
135 | 'SSL connection has been closed unexpectedly', |
||
136 | 'Deadlock found when trying to get lock', |
||
137 | ]); |
||
138 | } |
||
139 | } |
||
140 | |||
141 | View Code Duplication | abstract class Model implements ModelInterface |
|
0 ignored issues
–
show
This class 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. ![]() |
|||
142 | { |
||
143 | |||
144 | |||
145 | protected $properties = []; |
||
146 | |||
147 | /** |
||
148 | * Store instance of database connection used. |
||
149 | * @var [type] |
||
150 | */ |
||
151 | protected $databaseConnection; |
||
152 | |||
153 | public function __construct() |
||
154 | { |
||
155 | $this->databaseConnection = DatabaseConnection::getInstance()->databaseConnection; |
||
156 | //$databaseConnection->databaseConnection->connect(); |
||
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. ![]() |
|||
157 | } |
||
158 | /** |
||
159 | * @param string $key rep column name |
||
160 | * @param string $val rep column value |
||
161 | * sets into $propertie the $key => $value pairs |
||
162 | */ |
||
163 | public function __set($key, $val) |
||
164 | { |
||
165 | $this->properties[$key] = $val; |
||
166 | } |
||
167 | /** |
||
168 | * @param string $key reps the column name |
||
169 | * @return $key and $value |
||
0 ignored issues
–
show
The doc-type
$key could not be parsed: Unknown type name "$key" at position 0. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
170 | */ |
||
171 | public function __get($key) |
||
172 | { |
||
173 | return $this->properties[$key]; |
||
174 | } |
||
175 | /** |
||
176 | * Get all the model properties |
||
177 | * |
||
178 | * @return array |
||
179 | */ |
||
180 | public function getProperties() |
||
181 | { |
||
182 | return $this->properties; |
||
183 | } |
||
184 | /** |
||
185 | * Gets the name of the child class only |
||
186 | * without the namespace |
||
187 | * @var $className |
||
188 | * @var $table |
||
189 | * @return $table |
||
0 ignored issues
–
show
The doc-type
$table could not be parsed: Unknown type name "$table" at position 0. (view supported doc-types)
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types. ![]() |
|||
190 | */ |
||
191 | public function getTableName() |
||
192 | { |
||
193 | $className = explode('\\', get_called_class()); |
||
194 | $table = strtolower(end($className) .'s'); |
||
195 | return $table; |
||
196 | } |
||
197 | /** |
||
198 | * returns a particular record |
||
199 | * @param $id reps the record id |
||
200 | * @param $connection initialised to null |
||
201 | * @return object |
||
202 | */ |
||
203 | public static function find($id) |
||
204 | { |
||
205 | $model = new static; |
||
206 | return $model->get($id); |
||
207 | } |
||
208 | /** |
||
209 | * returns a particular record |
||
210 | * @param $id reps the record id |
||
211 | * @param $connection initialised to null |
||
212 | * @return object |
||
213 | */ |
||
214 | public function get($id) |
||
215 | { |
||
216 | $sql = "SELECT * FROM {$this->getTableName()} WHERE id={$id}"; |
||
217 | $sqlStatement = $this->databaseConnection->prepare($sql); |
||
218 | $sqlStatement->setFetchMode(PDO::FETCH_CLASS, get_called_class()); |
||
219 | $sqlStatement->execute(); |
||
220 | if($sqlStatement->rowCount() < 1){ |
||
221 | throw new ModelNotFoundException($id); |
||
222 | } |
||
223 | return $sqlStatement->fetch(); |
||
224 | } |
||
225 | |||
226 | public static function getAll() |
||
227 | { |
||
228 | $model = new static; |
||
229 | return $model->all(); |
||
230 | } |
||
231 | |||
232 | public function all() |
||
233 | { |
||
234 | $sql = "SELECT * FROM {$this->getTableName()}"; |
||
235 | $row = $this->databaseConnection->prepare($sql); |
||
236 | $row->execute(); |
||
237 | |||
238 | return $row->fetchAll($this->databaseConnection::FETCH_CLASS); |
||
239 | |||
240 | } |
||
241 | /** update table with instance properties |
||
242 | * |
||
243 | */ |
||
244 | private function update() |
||
245 | { |
||
246 | $connection = $this->getConnection(); |
||
247 | $columnNames = ""; |
||
0 ignored issues
–
show
$columnNames is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
248 | $columnValues = ""; |
||
0 ignored issues
–
show
$columnValues is not used, you could remove the assignment.
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently. $myVar = 'Value';
$higher = false;
if (rand(1, 6) > 3) {
$higher = true;
} else {
$higher = false;
}
Both the ![]() |
|||
249 | $count = 0; |
||
250 | $update = "UPDATE " . $this->getTableName() . " SET " ; |
||
251 | foreach ($this->properties as $key => $val) { |
||
252 | $count++; |
||
253 | if(($key == 'id')) continue; |
||
254 | $update .= "$key = '$val'"; |
||
255 | if ($count < count($this->properties) ) |
||
256 | { |
||
257 | $update .=","; |
||
258 | } |
||
259 | } |
||
260 | $update .= " WHERE id = " . $this->properties['id']; |
||
261 | $stmt = $connection->prepare($update); |
||
262 | foreach ($this->properties as $key => $val) { |
||
263 | if($key == 'id') continue; |
||
264 | } |
||
265 | $stmt->execute(); |
||
266 | return $stmt->rowCount(); |
||
267 | } |
||
268 | /** |
||
269 | * insert instance data into the table |
||
270 | */ |
||
271 | private function create() |
||
272 | { |
||
273 | $connection = $this->getConnection(); |
||
274 | $columnNames = ""; |
||
275 | $columnValues = ""; |
||
276 | $count = 0; |
||
277 | $create = "INSERT" . " INTO " . $this->getTableName()." ("; |
||
278 | foreach ($this->properties as $key => $val) { |
||
279 | $columnNames .= $key; |
||
280 | $columnValues .= ':' . $key; |
||
281 | $count++; |
||
282 | if ($count < count($this->properties)) |
||
283 | { |
||
284 | $columnNames .= ', '; |
||
285 | $columnValues .= ', '; |
||
286 | } |
||
287 | } |
||
288 | $create .= $columnNames.') VALUES (' .$columnValues.')'; |
||
289 | $stmt = $connection->prepare($create); |
||
290 | foreach ($this->properties as $key => $val) { |
||
291 | $stmt->bindValue(':'.$key, $val); |
||
292 | } |
||
293 | try { |
||
294 | // if prop returned and props from db differ throw exception |
||
295 | $stmt->execute(); |
||
296 | } catch(PDOException $e){ |
||
297 | return $e->getExceptionMessage(); |
||
298 | } |
||
299 | return $stmt->rowCount(); |
||
300 | } |
||
301 | /** |
||
302 | * get db connection |
||
303 | */ |
||
304 | public function getConnection($connection = null) |
||
305 | { |
||
306 | if(is_null($connection)) |
||
307 | { |
||
308 | return new Connection(); |
||
309 | } |
||
310 | } |
||
311 | /** |
||
312 | * checks if the id exists |
||
313 | * update if exist |
||
314 | * create if not exist |
||
315 | */ |
||
316 | public function save() |
||
317 | { |
||
318 | if ($this->id) { |
||
0 ignored issues
–
show
The property
id does not exist on object<Model> . Since you implemented __get , maybe consider adding a @property annotation.
Since your code implements the magic getter <?php
/**
* @property int $x
* @property int $y
* @property string $text
*/
class MyLabel
{
private $properties;
private $allowedProperties = array('x', 'y', 'text');
public function __get($name)
{
if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
return $properties[$name];
} else {
return null;
}
}
public function __set($name, $value)
{
if (in_array($name, $this->allowedProperties)) {
$properties[$name] = $value;
} else {
throw new \LogicException("Property $name is not defined.");
}
}
}
If the property has read access only, you can use the @property-read annotation instead. Of course, you may also just have mistyped another name, in which case you should fix the error. See also the PhpDoc documentation for @property. ![]() |
|||
319 | $this->update(); |
||
320 | } else { |
||
321 | $this->create(); |
||
322 | } |
||
323 | } |
||
324 | /** |
||
325 | * @param row reps record id |
||
326 | * @param $connection initialised to null |
||
327 | * @return boolean |
||
328 | */ |
||
329 | public static function destroy($id) |
||
330 | { |
||
331 | |||
332 | $sql = "DELETE" . " FROM " . self::getTableName()." WHERE id = ". $id; |
||
333 | $delete = $connection->prepare($sql); |
||
0 ignored issues
–
show
|
|||
334 | $delete->execute(); |
||
335 | $count = $delete->rowCount(); |
||
336 | if ($count < 1) { |
||
337 | throw new RecordNotFoundException('Record with id ' . $id . ' does not exist.'); |
||
338 | } |
||
339 | return ($count > 0) ? true : false; |
||
340 | } |
||
341 | |||
342 | /** |
||
343 | * Handle dynamic static method calls into the method. |
||
344 | * |
||
345 | * @param string $method |
||
346 | * @param array $parameters |
||
347 | * @return mixed |
||
348 | */ |
||
349 | public static function __callStatic($method, $parameters) |
||
0 ignored issues
–
show
|
|||
350 | { |
||
351 | exit("HERE"); |
||
352 | $instance = new static; |
||
0 ignored issues
–
show
$instance = new static(); does not seem to be reachable.
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed. Unreachable code is most often the result of function fx() {
try {
doSomething();
return true;
}
catch (\Exception $e) {
return false;
}
return false;
}
In the above example, the last ![]() |
|||
353 | |||
354 | return call_user_func_array([$instance, $method], $parameters); |
||
355 | } |
||
356 | } |
||
357 | |||
358 | interface ModelInterface { |
||
359 | /** |
||
360 | * Get all models from database. |
||
361 | * |
||
362 | * @return array |
||
363 | */ |
||
364 | static function getAll(); |
||
365 | |||
366 | /** |
||
367 | * Find model with the specified id. |
||
368 | */ |
||
369 | static function find($id); |
||
370 | |||
371 | /** |
||
372 | * Delete model with the specified id. |
||
373 | * |
||
374 | */ |
||
375 | static function destroy($id); |
||
376 | } |
||
377 | |||
378 | View Code Duplication | class DatabaseConnectionStringFactory implements DatabaseConnectionStringFactoryInterface |
|
0 ignored issues
–
show
This class 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. ![]() |
|||
379 | { |
||
380 | /** |
||
381 | * Create a connection string |
||
382 | * |
||
383 | * @param array $config |
||
384 | * @throws Pyjac\PotatoORM\Exception\DatabaseDriverNotSupportedException |
||
385 | * @return string |
||
386 | */ |
||
387 | public function createDatabaseSourceString($config) |
||
388 | { |
||
389 | |||
390 | $driver = $config['DRIVER']; |
||
391 | |||
392 | switch ($driver) { |
||
393 | case 'sqlite': |
||
394 | $dsn = $driver.'::memory:'; |
||
395 | break; |
||
396 | case 'mysql': |
||
397 | case 'postgres': |
||
398 | if(strcasecmp($driver, 'postgres') == 0) $driver="pgsql"; |
||
399 | $dsn = $driver.':host='.$config['HOSTNAME'].';dbname='.$config['DBNAME']; |
||
400 | if(isset($config['PORT'])) $dsn .= ';port='.$config['PORT']; |
||
401 | break; |
||
402 | default: |
||
403 | throw new DatabaseDriverNotSupportedException; |
||
404 | } |
||
405 | return $dsn; |
||
406 | } |
||
407 | } |
||
408 | |||
409 | interface DatabaseConnectionStringFactoryInterface |
||
410 | { |
||
411 | /** |
||
412 | * Create a connection string |
||
413 | * |
||
414 | * @param array $config |
||
415 | * @throws Pyjac\PotatoORM\Exception\DatabaseDriverNotSupportedException |
||
416 | * @return string |
||
417 | */ |
||
418 | public function createDatabaseSourceString($config); |
||
419 | } |
||
420 | |||
421 | |||
422 | |||
423 | class DatabaseDriverNotSupportedException extends Exception |
||
424 | { |
||
425 | |||
426 | function __construct() |
||
0 ignored issues
–
show
|
|||
427 | { |
||
428 | parent::__construct("Database driver not supported."); |
||
429 | } |
||
430 | } |
||
431 | |||
432 | class ModelNotFoundException extends Exception |
||
433 | { |
||
434 | |||
435 | function __construct($id) |
||
0 ignored issues
–
show
|
|||
436 | { |
||
437 | parent::__construct('The requested Model with ' . $id . ' does not exist'); |
||
438 | } |
||
439 | } |
||
440 | |||
441 | View Code Duplication | class Helpers |
|
0 ignored issues
–
show
This class 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. ![]() |
|||
442 | { |
||
443 | |||
444 | /** |
||
445 | * Determine if a given string contains a given substring. |
||
446 | * |
||
447 | * @param string $haystack |
||
448 | * @param string|array $needles |
||
449 | * @return bool |
||
450 | */ |
||
451 | public static function contains($haystack, $needles) |
||
452 | { |
||
453 | foreach ((array) $needles as $needle) { |
||
454 | if ($needle != '' && strpos($haystack, $needle) !== false) { |
||
455 | return true; |
||
456 | } |
||
457 | } |
||
458 | |||
459 | return false; |
||
460 | } |
||
461 | } |
||
462 | |||
463 | class User extends Model { |
||
0 ignored issues
–
show
Comprehensibility
Best Practice
introduced
by
The type
User has been defined more than once; this definition is ignored, only the first definition in index.php (L7-9) is considered.
This check looks for classes that have been defined more than once. If you can, we would recommend to use standard object-oriented programming techniques. For example, to avoid multiple types, it might make sense to create a common interface, and then multiple, different implementations for that interface. This also has the side-effect of providing you with better IDE auto-completion, static analysis and also better OPCode caching from PHP. ![]() |
|||
464 | |||
465 | } |
||
466 | |||
467 | $users = User::getAll(); |
||
468 | var_dump($users); |
||
0 ignored issues
–
show
|
|||
469 | var_dump(User::find(1)); |
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.