andela-joyebanji /
PotatoORM
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | |||
| 4 | interface ModelInterface { |
||
| 5 | /** |
||
| 6 | * Get all models from database. |
||
| 7 | * |
||
| 8 | * @return array |
||
| 9 | */ |
||
| 10 | function static getAll(); |
||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
| 11 | |||
| 12 | /** |
||
| 13 | * Find model with the specified id. |
||
| 14 | */ |
||
| 15 | function static find($id); |
||
| 16 | |||
| 17 | /** |
||
| 18 | * Delete model with the specified id. |
||
| 19 | * |
||
| 20 | */ |
||
| 21 | function static destroy($id); |
||
| 22 | } |
||
| 23 | |||
| 24 | abstract Model { |
||
| 25 | |||
| 26 | /** |
||
| 27 | * The connection name for the model. |
||
| 28 | * |
||
| 29 | * @var string |
||
| 30 | */ |
||
| 31 | protected $connection; |
||
| 32 | |||
| 33 | |||
| 34 | } |
||
| 35 | |||
| 36 | class DatabaseConnectionFactory { |
||
| 37 | |||
| 38 | |||
| 39 | |||
| 40 | |||
| 41 | } |
||
| 42 | |||
| 43 | |||
| 44 | class Connection { |
||
| 45 | |||
| 46 | /** |
||
| 47 | * The current globally used instance. |
||
| 48 | * |
||
| 49 | * @var object |
||
| 50 | */ |
||
| 51 | protected static $instance; |
||
| 52 | |||
| 53 | private $host; |
||
| 54 | private $user; |
||
| 55 | private $pass; |
||
| 56 | private $dbname; |
||
| 57 | |||
| 58 | private $dbh; |
||
| 59 | private $error; |
||
| 60 | |||
| 61 | public function __construct(){ |
||
| 62 | $config = parse_ini_file('config.ini'); |
||
| 63 | // Set DSN |
||
| 64 | $dsn = 'mysql:host=' . $this->host . ';dbname=' . $this->dbname; |
||
| 65 | // Set options |
||
| 66 | $options = array( |
||
| 67 | PDO::ATTR_PERSISTENT => true, |
||
| 68 | PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION |
||
| 69 | ); |
||
| 70 | // Create a new PDO instanace |
||
| 71 | try{ |
||
| 72 | $this->dbh = new PDO($dsn, $this->user, $this->pass, $options); |
||
| 73 | } |
||
| 74 | // Catch any errors |
||
| 75 | catch(PDOException $e){ |
||
| 76 | $this->error = $e->getMessage(); |
||
| 77 | } |
||
| 78 | } |
||
| 79 | } |
||
| 80 | |||
| 81 | |||
| 82 | try { |
||
| 83 | |||
| 84 | $dbh = new PDO('mysql:host=localhost;dbname=potatoORM', 'homestead', 'secret'); |
||
| 85 | foreach($dbh->query('SELECT * from test') as $row) { |
||
| 86 | print_r($row); |
||
| 87 | } |
||
| 88 | } catch (PDOException $e) { |
||
| 89 | print "Error!: " . $e->getMessage() . "<br/>"; |
||
| 90 | die(); |
||
| 91 | } |
||
| 92 | |||
| 93 | $stmt = $dbh->prepare("INSERT INTO test (id, body) VALUES (?, ?)"); |
||
| 94 | $stmt->bindParam(1, $id); |
||
| 95 | $stmt->bindParam(2, $body); |
||
| 96 | |||
| 97 | // insert one row |
||
| 98 | $id = 3; |
||
| 99 | $body = 'Some other test msg'; |
||
| 100 | $stmt->execute(); |
||
| 101 | |||
| 102 | // insert another row with different values |
||
| 103 | $id = 4; |
||
| 104 | $body = 'Some other test msg 2'; |
||
| 105 | $stmt->execute(); |
||
| 106 | $dbh = null; |
||
| 107 | |||
| 108 | class Model { |
||
| 109 | |||
| 110 | |||
| 111 | |||
| 112 | function __construct() |
||
|
0 ignored issues
–
show
|
|||
| 113 | { |
||
| 114 | /** |
||
| 115 | * Load the environment variables |
||
| 116 | * @return connection object |
||
| 117 | */ |
||
| 118 | $this->loadDotenv(); |
||
| 119 | |||
| 120 | $this->database = getenv('DB_DATABASE'); |
||
| 121 | $this->host = getenv('DB_host'); |
||
| 122 | $this->username = getenv('DB_USERNAME'); |
||
| 123 | $this->password = getenv('DB_PASSWORD'); |
||
| 124 | $this->driver = getenv('DB_CONNECTION'); |
||
| 125 | |||
| 126 | } |
||
| 127 | /** |
||
| 128 | * use vlucas dotenv to access the .env file |
||
| 129 | **/ |
||
| 130 | protected function loadDotenv() |
||
| 131 | { |
||
| 132 | if(getenv('APP_ENV') !== 'production') |
||
| 133 | { |
||
| 134 | $dotenv = new Dotenv(__DIR__); |
||
| 135 | $dotenv->load(); |
||
| 136 | } |
||
| 137 | } |
||
| 138 | |||
| 139 | /** |
||
| 140 | * Handle dynamic static method calls into the method. |
||
| 141 | * |
||
| 142 | * @param string $method |
||
| 143 | * @param array $parameters |
||
| 144 | * @return mixed |
||
| 145 | */ |
||
| 146 | public static function __callStatic($method, $parameters) |
||
| 147 | { |
||
| 148 | $instance = new static; |
||
| 149 | |||
| 150 | return call_user_func_array([$instance, $method], $parameters); |
||
| 151 | } |
||
| 152 | |||
| 153 | } |
||
| 154 | |||
| 155 | |||
| 156 | class MySqlConnector extends DatabaseAdapter implements DatabaseAdapterInterface |
||
| 157 | { |
||
| 158 | /** |
||
| 159 | * Establish a database connection. |
||
| 160 | * |
||
| 161 | * @param array $config |
||
| 162 | * @return \PDO |
||
| 163 | */ |
||
| 164 | public function connect(array $config) |
||
| 165 | { |
||
| 166 | $dsn = $this->getDsn($config); |
||
| 167 | |||
| 168 | $options = $this->getOptions($config); |
||
| 169 | |||
| 170 | // We need to grab the PDO options that should be used while making the brand |
||
| 171 | // new connection instance. The PDO options control various aspects of the |
||
| 172 | // connection's behavior, and some might be specified by the developers. |
||
| 173 | $connection = $this->createConnection($dsn, $config, $options); |
||
| 174 | |||
| 175 | $collation = $config['collation']; |
||
| 176 | |||
| 177 | // Next we will set the "names" and "collation" on the clients connections so |
||
| 178 | // a correct character set will be used by this client. The collation also |
||
| 179 | // is set on the server but needs to be set here on this client objects. |
||
| 180 | $charset = $config['charset']; |
||
| 181 | |||
| 182 | $names = "set names '$charset'". |
||
| 183 | (! is_null($collation) ? " collate '$collation'" : ''); |
||
| 184 | |||
| 185 | $connection->prepare($names)->execute(); |
||
| 186 | |||
| 187 | return $connection; |
||
| 188 | } |
||
| 189 | |||
| 190 | /** |
||
| 191 | * Create a DSN string from a configuration. |
||
| 192 | * |
||
| 193 | * Chooses socket or host/port based on the 'unix_socket' config value. |
||
| 194 | * |
||
| 195 | * @param array $config |
||
| 196 | * @return string |
||
| 197 | */ |
||
| 198 | protected function getDsn(array $config) |
||
| 199 | { |
||
| 200 | return $this->configHasSocket($config) ? $this->getSocketDsn($config) : $this->getHostDsn($config); |
||
| 201 | } |
||
| 202 | |||
| 203 | /** |
||
| 204 | * Determine if the given configuration array has a UNIX socket value. |
||
| 205 | * |
||
| 206 | * @param array $config |
||
| 207 | * @return bool |
||
| 208 | */ |
||
| 209 | protected function configHasSocket(array $config) |
||
| 210 | { |
||
| 211 | return isset($config['unix_socket']) && ! empty($config['unix_socket']); |
||
| 212 | } |
||
| 213 | |||
| 214 | /** |
||
| 215 | * Get the DSN string for a socket configuration. |
||
| 216 | * |
||
| 217 | * @param array $config |
||
| 218 | * @return string |
||
| 219 | */ |
||
| 220 | protected function getSocketDsn(array $config) |
||
| 221 | { |
||
| 222 | return "mysql:unix_socket={$config['unix_socket']};dbname={$config['database']}"; |
||
| 223 | } |
||
| 224 | |||
| 225 | /** |
||
| 226 | * Get the DSN string for a host / port configuration. |
||
| 227 | * |
||
| 228 | * @param array $config |
||
| 229 | * @return string |
||
| 230 | */ |
||
| 231 | protected function getHostDsn(array $config) |
||
| 232 | { |
||
| 233 | extract($config, EXTR_SKIP); |
||
| 234 | |||
| 235 | return isset($port) |
||
| 236 | ? "mysql:host={$host};port={$port};dbname={$database}" |
||
| 237 | : "mysql:host={$host};dbname={$database}"; |
||
| 238 | } |
||
| 239 | } |
||
| 240 | |||
| 241 | |||
| 242 | interface DatabaseAdapterInterface |
||
| 243 | { |
||
| 244 | /** |
||
| 245 | * Establish a database connection. |
||
| 246 | * |
||
| 247 | * @param array $config |
||
| 248 | * @return \PDO |
||
| 249 | */ |
||
| 250 | public function connect(array $config); |
||
| 251 | } |
||
| 252 | |||
| 253 | |||
| 254 | class DatabaseConnection |
||
| 255 | { |
||
| 256 | /** |
||
| 257 | * [$instance description] |
||
| 258 | * @var [type] |
||
| 259 | */ |
||
| 260 | private static $instance; |
||
| 261 | |||
| 262 | /** |
||
| 263 | * [$databaseConnection description] |
||
| 264 | * @var [type] |
||
| 265 | */ |
||
| 266 | private $databaseConnection; |
||
| 267 | |||
| 268 | /** |
||
| 269 | * The default PDO connection options. |
||
| 270 | * |
||
| 271 | * @var array |
||
| 272 | */ |
||
| 273 | protected $options = [ |
||
| 274 | PDO::ATTR_CASE => PDO::CASE_NATURAL, |
||
| 275 | PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, |
||
| 276 | PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL, |
||
| 277 | PDO::ATTR_STRINGIFY_FETCHES => false, |
||
| 278 | PDO::ATTR_EMULATE_PREPARES => false, |
||
| 279 | ]; |
||
| 280 | |||
| 281 | /** |
||
| 282 | * Singleton Class: |
||
| 283 | * Constructor reads database config file and creates connection. |
||
| 284 | */ |
||
| 285 | private function __construct(DatabaseConnectionStringFactoryInterface $dbConnStringFactory) |
||
| 286 | { |
||
| 287 | //Read config file |
||
| 288 | $this->config = parse_ini_file('config.ini'); |
||
| 289 | $dsn = $dbConnStringFactory->createDatabaseSourceString($this->config); |
||
| 290 | $this->createConnection($dsn, $this->options); |
||
| 291 | } |
||
| 292 | |||
| 293 | public static function getInstance() |
||
| 294 | { |
||
| 295 | if (self::$instance === null) { |
||
| 296 | self::$instance = new self(new DatabaseConnectionStringFactory); |
||
| 297 | } |
||
| 298 | return self::$instance; |
||
| 299 | } |
||
| 300 | |||
| 301 | |||
| 302 | /** |
||
| 303 | * Create a new PDO connection. |
||
| 304 | * |
||
| 305 | * @param string $dsn |
||
| 306 | * @param array $config |
||
| 307 | * @return \PDO |
||
| 308 | */ |
||
| 309 | public function createConnection($dsn, array $config) |
||
| 310 | { |
||
| 311 | $username = $this->config['USERNAME']; |
||
| 312 | |||
| 313 | $password = $this->config['PASSWORD']; |
||
| 314 | |||
| 315 | try { |
||
| 316 | $pdo = new PDO($dsn, $username, $password, $options); |
||
| 317 | } catch (Exception $e) { |
||
| 318 | $pdo = $this->tryAgainIfCausedByLostConnection( |
||
| 319 | $e, $dsn, $username, $password, $options |
||
| 320 | ); |
||
| 321 | } |
||
| 322 | |||
| 323 | return $pdo; |
||
| 324 | } |
||
| 325 | |||
| 326 | /** |
||
| 327 | * Get the default PDO connection options. |
||
| 328 | * |
||
| 329 | * @return array |
||
| 330 | */ |
||
| 331 | public function getDefaultOptions() |
||
| 332 | { |
||
| 333 | return $this->options; |
||
| 334 | } |
||
| 335 | |||
| 336 | /** |
||
| 337 | * Set the default PDO connection options. |
||
| 338 | * |
||
| 339 | * @param array $options |
||
| 340 | * @return void |
||
| 341 | */ |
||
| 342 | public function setDefaultOptions(array $options) |
||
| 343 | { |
||
| 344 | $this->options = $options; |
||
| 345 | } |
||
| 346 | |||
| 347 | /** |
||
| 348 | * Handle a exception that occurred during connect execution. |
||
| 349 | * |
||
| 350 | * @param \Exception $e |
||
| 351 | * @param string $dsn |
||
| 352 | * @param string $username |
||
| 353 | * @param string $password |
||
| 354 | * @param array $options |
||
| 355 | * @return \PDO |
||
| 356 | * |
||
| 357 | * @throws \Exception |
||
| 358 | */ |
||
| 359 | protected function tryAgainIfCausedByLostConnection(Exception $e, $dsn, $username, $password, $options) |
||
| 360 | { |
||
| 361 | if ($this->causedByLostConnection($e)) { |
||
| 362 | return new PDO($dsn, $username, $password, $options); |
||
| 363 | } |
||
| 364 | |||
| 365 | throw $e; |
||
| 366 | } |
||
| 367 | |||
| 368 | /** |
||
| 369 | * Determine if the given exception was caused by a lost connection. |
||
| 370 | * |
||
| 371 | * @param \Exception $e |
||
| 372 | * @return bool |
||
| 373 | */ |
||
| 374 | protected function causedByLostConnection(Exception $e) |
||
| 375 | { |
||
| 376 | $message = $e->getMessage(); |
||
| 377 | |||
| 378 | return Helpers::contains($message, [ |
||
| 379 | 'server has gone away', |
||
| 380 | 'no connection to the server', |
||
| 381 | 'Lost connection', |
||
| 382 | 'is dead or not enabled', |
||
| 383 | 'Error while sending', |
||
| 384 | 'decryption failed or bad record mac', |
||
| 385 | 'SSL connection has been closed unexpectedly', |
||
| 386 | 'Deadlock found when trying to get lock', |
||
| 387 | ]); |
||
| 388 | } |
||
| 389 | } |
||
| 390 | |||
| 391 | |||
| 392 | class Helpers { |
||
| 393 | |||
| 394 | /** |
||
| 395 | * Determine if a given string contains a given substring. |
||
| 396 | * |
||
| 397 | * @param string $haystack |
||
| 398 | * @param string|array $needles |
||
| 399 | * @return bool |
||
| 400 | */ |
||
| 401 | public static function contains($haystack, $needles) |
||
| 402 | { |
||
| 403 | foreach ((array) $needles as $needle) { |
||
| 404 | if ($needle != '' && strpos($haystack, $needle) !== false) { |
||
| 405 | return true; |
||
| 406 | } |
||
| 407 | } |
||
| 408 | |||
| 409 | return false; |
||
| 410 | } |
||
| 411 | } |