Completed
Branch develop (32cfca)
by Oyebanji Jacob
03:26
created

DatabaseConnection::getInstance()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 4

Duplication

Lines 7
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 7
loc 7
rs 9.4285
cc 2
eloc 4
nc 2
nop 0
1
<?php
2
3
namespace Pyjac\ORM;
4
5
use PDO;
6
use Pyjac\ORM\DatabaseConnectionStringFactoryInterface;
7
use Pyjac\ORM\DatabaseConnectionStringFactory;
8
9 View Code Duplication
class DatabaseConnection
0 ignored issues
show
Duplication introduced by
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.

Loading history...
10
{
11
    /**
12
     * The instance of this class.
13
     * 
14
     * @var Pyjac\ORM\DatabaseConnection.
15
     */
16
    private static $instance;
17
18
    /**
19
     * The PDO database connection in use.
20
     * 
21
     * @var \PDO
22
     */
23
    public $databaseConnection;
24
25
    /**
26
     * The default PDO connection options.
27
     *
28
     * @var array
29
     */
30
    protected $options = [
31
        PDO::ATTR_CASE => PDO::CASE_NATURAL,
32
        PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
33
        PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
34
        PDO::ATTR_STRINGIFY_FETCHES => false,
35
        PDO::ATTR_EMULATE_PREPARES => false,
36
    ];
37
38
    /**
39
     * Create a new Database Connection.
40
     * 
41
     * @param DatabaseConnectionStringFactoryInterface $dbConnStringFactory
42
     */
43
    private function __construct(DatabaseConnectionStringFactoryInterface $dbConnStringFactory)
44
    {
45
        //Read config file
46
        $this->config = parse_ini_file('config.ini');
0 ignored issues
show
Bug introduced by
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;
Loading history...
47
        $dsn = $dbConnStringFactory->createDatabaseSourceString($this->config);
48
        $this->databaseConnection = $this->createConnection($dsn, $this->options);
49
    }
50
51
    /**
52
     * Get the instance of the class.
53
     *     
54
     * @return Pyjac\ORM\DatabaseConnection
55
     */
56
    public static function getInstance()
57
    {
58
        if (self::$instance === null) {
59
            self::$instance = new self(new DatabaseConnectionStringFactory);
60
        }
61
        return self::$instance;
62
    }
63
    
64
65
    /**
66
     * Create a new PDO connection.
67
     *
68
     * @param  string  $dsn
69
     * @param  array   $config
70
     * @return \PDO
71
     */
72
    public function createConnection($dsn, array $config)
0 ignored issues
show
Unused Code introduced by
The parameter $config is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
73
    {
74
        $username = $this->config['USERNAME'];
75
76
        $password = $this->config['PASSWORD'];
77
        
78
79
        try {
80
            $pdo = new PDO($dsn, $username, $password, $this->options);
81
        } catch (\Exception $e) {
82
            $pdo = $this->tryAgainIfCausedByLostConnection(
83
                $e, $dsn, $username, $password, $options
0 ignored issues
show
Bug introduced by
The variable $options does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
Documentation introduced by
$e is of type object<Exception>, but the function expects a object<Pyjac\ORM\Exception>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
84
            );
85
        }
86
87
        return $pdo;
88
    }
89
90
    /**
91
     * Get the default PDO connection options.
92
     *
93
     * @return array
94
     */
95
    public function getDefaultOptions()
96
    {
97
        return $this->options;
98
    }
99
100
    /**
101
     * Set the default PDO connection options.
102
     *
103
     * @param  array  $options
104
     * @return void
105
     */
106
    public function setDefaultOptions(array $options)
107
    {
108
        $this->options = $options;
109
    }
110
111
    /**
112
     * Handle a exception that occurred during connect execution.
113
     *
114
     * @param  \Exception  $e
115
     * @param  string  $dsn
116
     * @param  string  $username
117
     * @param  string  $password
118
     * @param  array   $options
119
     * @return \PDO
120
     *
121
     * @throws \Exception
122
     */
123
    protected function tryAgainIfCausedByLostConnection(Exception $e, $dsn, $username, $password, $options)
124
    {
125
        if ($this->causedByLostConnection($e)) {
126
            return new PDO($dsn, $username, $password, $options);
127
        }
128
129
        throw $e;
130
    }
131
132
    /**
133
     * Determine if the given exception was caused by a lost connection.
134
     *
135
     * @param  \Exception  $e
136
     * @return bool
137
     */
138
    protected function causedByLostConnection(Exception $e)
139
    {
140
        $message = $e->getMessage();
141
142
        return Helpers::contains($message, [
143
            'server has gone away',
144
            'no connection to the server',
145
            'Lost connection',
146
            'is dead or not enabled',
147
            'Error while sending',
148
            'decryption failed or bad record mac',
149
            'SSL connection has been closed unexpectedly',
150
            'Deadlock found when trying to get lock',
151
        ]);
152
    }
153
}
154