Test Setup Failed
Push — master ( 455f41...6456b5 )
by Gabriel
11:14 queued 12s
created

ConnectionFactory   A

Complexity

Total Complexity 24

Size/Duplication

Total Lines 196
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 3

Test Coverage

Coverage 0%

Importance

Changes 0
Metric Value
wmc 24
lcom 2
cbo 3
dl 0
loc 196
ccs 0
cts 17
cp 0
rs 10
c 0
b 0
f 0

10 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 2
A make() 0 9 1
A parseConfig() 0 5 1
A createSingleConnection() 0 11 2
A createConnection() 0 12 2
A createPdoResolver() 0 8 3
A createPdoResolverWithHosts() 0 16 3
A parseHosts() 0 10 2
A createPdoResolverWithoutHosts() 0 6 1
B createConnector() 0 23 7
1
<?php
2
3
namespace Nip\Database\Connections;
4
5
use InvalidArgumentException;
6
use Nip\Config\Config;
7
use Nip\Container\Container;
8
use Nip\Utility\Arr;
9
use PDOException;
10
11
/**
12
 * Class ConnectionFactory
13
 * @package Nip\Database\Connectors
14
 */
15
class ConnectionFactory
16
{
17
    /**
18
     * The IoC container instance.
19
     *
20
     * @var Container
21
     */
22
    protected $container;
23
24
    /**
25
     * Create a new connection factory instance.
26
     *
27
     * @param  Container $container
28
     */
29
    public function __construct(Container $container = null)
30
    {
31
        $this->container = $container ? $container : Container::getInstance();
32
    }
33
34
    /**
35
     * Establish a PDO connection based on the configuration.
36
     *
37
     * @param  array $config
38
     * @param  string $name
39
     * @return Connection
40
     */
41
    public function make($config, $name = null)
42
    {
43
        $config = $this->parseConfig($config, $name);
44
45
//        if (isset($config['read'])) {
46
//            return $this->createReadWriteConnection($config);
47
//        }
48
        return $this->createSingleConnection($config);
49
    }
50
51
    /**
52
     * Parse and prepare the database configuration.
53
     *
54
     * @param  array $config
55
     * @param  string $name
56
     * @return array
57
     */
58
    protected function parseConfig($config, $name)
0 ignored issues
show
Unused Code introduced by
The parameter $name 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...
59
    {
60
        return $config;
61
//        return Arr::add(Arr::add($config, 'prefix', ''), 'name', $name);
62
    }
63
64
    /**
65
     * Create a single database connection instance.
66
     *
67
     * @param  array $config
68
     * @return Connection
69
     */
70
    protected function createSingleConnection($config)
71
    {
72
        $pdo = $this->createPdoResolver($config);
73
        if (!isset($config['driver'])) {
74
            $config['driver'] = 'mysql';
75
        }
76
        $connection = $this->createConnection($config['driver'], $pdo, $config['database'], $config['prefix'], $config);
0 ignored issues
show
Documentation introduced by
$pdo is of type object<Closure>, but the function expects a boolean.

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...
77
        $connection->connect($config['host'], $config['username'], $config['password'], $config['database']);
78
79
        return $connection;
80
    }
81
82
    /**
83
     * Create a new connection instance.
84
     *
85
     * @param  string $driver
86
     * @param  boolean $connection
87
     * @param  string $database
88
     * @param  string $prefix
89
     * @param  array $config
90
     * @return Connection
91
     *
92
     * @throws \InvalidArgumentException
93
     */
94
    protected function createConnection($driver, $connection, $database, $prefix = '', $config = [])
95
    {
96
//        if ($resolver = Connection::getResolver($driver)) {
97
//            return $resolver($connection, $database, $prefix, $config);
98
//        }
99
        switch ($driver) {
100
            case 'mysql':
101
                return new MySqlConnection($connection, $database, $prefix, $config);
0 ignored issues
show
Documentation introduced by
$connection is of type boolean, but the function expects a object<PDO>|object<Closure>.

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...
102
        }
103
104
        throw new InvalidArgumentException("Unsupported driver [$driver]");
105
    }
106
107
    /**
108
     * Create a new Closure that resolves to a PDO instance.
109
     *
110
     * @param  array|Config  $config
111
     * @return \Closure
112
     */
113
    protected function createPdoResolver($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...
114
    {
115
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type documented by Nip\Database\Connections...tory::createPdoResolver of type Closure.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
116
        $config = $config instanceof Config ? $config->toArray() : $config;
0 ignored issues
show
Unused Code introduced by
$config = $config instan...g->toArray() : $config; 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 return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
117
        return array_key_exists('host', $config)
118
            ? $this->createPdoResolverWithHosts($config)
119
            : $this->createPdoResolverWithoutHosts($config);
120
    }
121
122
    /**
123
     * Create a new Closure that resolves to a PDO instance with a specific host or an array of hosts.
124
     *
125
     * @param  array  $config
126
     * @return \Closure
127
     *
128
     * @throws \PDOException
129
     */
130
    protected function createPdoResolverWithHosts(array $config)
131
    {
132
        return function () use ($config) {
133
            foreach (Arr::shuffle($hosts = $this->parseHosts($config)) as $key => $host) {
134
                $config['host'] = $host;
135
136
                try {
137
                    return $this->createConnector($config)->connect($config);
138
                } catch (PDOException $e) {
139
                    continue;
140
                }
141
            }
142
143
            throw $e;
144
        };
145
    }
146
147
    /**
148
     * Parse the hosts configuration item into an array.
149
     *
150
     * @param  array  $config
151
     * @return array
152
     *
153
     * @throws \InvalidArgumentException
154
     */
155
    protected function parseHosts(array $config)
156
    {
157
        $hosts = Arr::wrap($config['host']);
158
159
        if (empty($hosts)) {
160
            throw new InvalidArgumentException('Database hosts array is empty.');
161
        }
162
163
        return $hosts;
164
    }
165
166
    /**
167
     * Create a new Closure that resolves to a PDO instance where there is no configured host.
168
     *
169
     * @param  array  $config
170
     * @return \Closure
171
     */
172
    protected function createPdoResolverWithoutHosts(array $config)
173
    {
174
        return function () use ($config) {
175
            return $this->createConnector($config)->connect($config);
176
        };
177
    }
178
179
    /**
180
     * Create a connector instance based on the configuration.
181
     *
182
     * @param  array  $config
183
     * @return \Illuminate\Database\Connectors\ConnectorInterface
184
     *
185
     * @throws \InvalidArgumentException
186
     */
187
    public function createConnector(array $config)
188
    {
189
        if (! isset($config['driver'])) {
190
            throw new InvalidArgumentException('A driver must be specified.');
191
        }
192
193
        if ($this->container->bound($key = "db.connector.{$config['driver']}")) {
0 ignored issues
show
Bug introduced by
The method bound() does not seem to exist on object<Nip\Container\Container>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
194
            return $this->container->make($key);
0 ignored issues
show
Bug introduced by
The method make() does not seem to exist on object<Nip\Container\Container>.

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
195
        }
196
197
        switch ($config['driver']) {
198
            case 'mysql':
199
                return new MySqlConnector;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \Nip\Database...tions\MySqlConnector(); (Nip\Database\Connections\MySqlConnector) is incompatible with the return type documented by Nip\Database\Connections...actory::createConnector of type Illuminate\Database\Connectors\ConnectorInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
200
            case 'pgsql':
201
                return new PostgresConnector;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \Nip\Database...ns\PostgresConnector(); (Nip\Database\Connections\PostgresConnector) is incompatible with the return type documented by Nip\Database\Connections...actory::createConnector of type Illuminate\Database\Connectors\ConnectorInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
202
            case 'sqlite':
203
                return new SQLiteConnector;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \Nip\Database...ions\SQLiteConnector(); (Nip\Database\Connections\SQLiteConnector) is incompatible with the return type documented by Nip\Database\Connections...actory::createConnector of type Illuminate\Database\Connectors\ConnectorInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
204
            case 'sqlsrv':
205
                return new SqlServerConnector;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \Nip\Database...s\SqlServerConnector(); (Nip\Database\Connections\SqlServerConnector) is incompatible with the return type documented by Nip\Database\Connections...actory::createConnector of type Illuminate\Database\Connectors\ConnectorInterface.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
206
        }
207
208
        throw new InvalidArgumentException("Unsupported driver [{$config['driver']}].");
209
    }
210
}
211