Completed
Push — master ( 4b502b...cb8c96 )
by Elan
18s queued 10s
created

ServiceContainer::setupPaths()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.9666
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
namespace XHGui;
4
5
use MongoClient;
6
use MongoCollection;
7
use MongoDB;
8
use MongoDB\Driver\Manager;
9
use PDO;
10
use Pimple\Container;
11
use RuntimeException;
12
use Slim\Middleware\SessionCookie;
13
use Slim\Slim as App;
14
use Slim\Views\Twig;
15
use XHGui\Db\PdoRepository;
16
use XHGui\Middleware\RenderMiddleware;
17
use XHGui\Saver\NormalizingSaver;
18
use XHGui\Searcher\MongoSearcher;
19
use XHGui\Searcher\PdoSearcher;
20
use XHGui\ServiceProvider\ConfigProvider;
21
use XHGui\ServiceProvider\RouteProvider;
22
use XHGui\Twig\TwigExtension;
23
24
class ServiceContainer extends Container
25
{
26
    /** @var self */
27
    protected static $_instance;
28
29
    /**
30
     * @return self
31
     */
32
    public static function instance()
33
    {
34
        if (empty(static::$_instance)) {
35
            static::$_instance = new self();
36
            static::$_instance->boot();
37
        }
38
39
        return static::$_instance;
40
    }
41
42
    public function __construct()
43
    {
44
        parent::__construct();
45
        $this->setupPaths($this);
0 ignored issues
show
Documentation introduced by
$this is of type this<XHGui\ServiceContainer>, but the function expects a object<self>.

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...
46
        $this->register(new ConfigProvider());
47
        $this->_slimApp();
0 ignored issues
show
Unused Code introduced by
The call to the method XHGui\ServiceContainer::_slimApp() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
48
        $this->_services();
0 ignored issues
show
Unused Code introduced by
The call to the method XHGui\ServiceContainer::_services() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
49
        $this->storageDriverPdo($this);
0 ignored issues
show
Unused Code introduced by
The call to the method XHGui\ServiceContainer::storageDriverPdo() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
50
        $this->storageDriverMongoDb($this);
0 ignored issues
show
Unused Code introduced by
The call to the method XHGui\ServiceContainer::storageDriverMongoDb() seems un-needed as the method has no side-effects.

PHP Analyzer performs a side-effects analysis of your code. A side-effect is basically anything that might be visible after the scope of the method is left.

Let’s take a look at an example:

class User
{
    private $email;

    public function getEmail()
    {
        return $this->email;
    }

    public function setEmail($email)
    {
        $this->email = $email;
    }
}

If we look at the getEmail() method, we can see that it has no side-effect. Whether you call this method or not, no future calls to other methods are affected by this. As such code as the following is useless:

$user = new User();
$user->getEmail(); // This line could safely be removed as it has no effect.

On the hand, if we look at the setEmail(), this method _has_ side-effects. In the following case, we could not remove the method call:

$user = new User();
$user->setEmail('email@domain'); // This line has a side-effect (it changes an
                                 // instance variable).
Loading history...
51
        $this->_controllers();
52
    }
53
54
    public function boot()
55
    {
56
        $this->register(new RouteProvider());
57
    }
58
59
    private function setupPaths(self $app)
60
    {
61
        $app['app.dir'] = dirname(__DIR__);
62
        $app['app.template_dir'] = dirname(__DIR__) . '/templates';
63
        $app['app.config_dir'] = dirname(__DIR__) . '/config';
64
        $app['app.cache_dir'] = static function ($c) {
65
            return $c['config']['cache'] ?? dirname(__DIR__) . '/cache';
66
        };
67
    }
68
69
    // Create the Slim app.
70
    protected function _slimApp()
71
    {
72
        $this['view'] = static function ($c) {
73
            // Configure Twig view for slim
74
            $view = new Twig();
75
76
            $view->twigTemplateDirs = [
77
                $c['app.template_dir'],
78
            ];
79
            $view->parserOptions = [
80
                'charset' => 'utf-8',
81
                'cache' => $c['app.cache_dir'],
82
                'auto_reload' => true,
83
                'strict_variables' => false,
84
                'autoescape' => true,
85
            ];
86
87
            return $view;
88
        };
89
90
        $this['app'] = static function ($c) {
91
            if ($c['config']['timezone']) {
92
                date_default_timezone_set($c['config']['timezone']);
93
            }
94
95
            $app = new App($c['config']);
96
97
            // Enable cookie based sessions
98
            $app->add(new SessionCookie([
99
                'httponly' => true,
100
            ]));
101
102
            // Add renderer.
103
            $app->add(new RenderMiddleware());
104
105
            $view = $c['view'];
106
            $view->parserExtensions = [
107
                new TwigExtension($app),
108
            ];
109
            $app->view($view);
110
111
            return $app;
112
        };
113
    }
114
115
    /**
116
     * Add common service objects to the container.
117
     */
118
    protected function _services()
119
    {
120
        $this['searcher'] = static function ($c) {
121
            $saver = $c['config']['save.handler'];
122
123
            return $c["searcher.$saver"];
124
        };
125
126
        $this['saver'] = static function ($c) {
127
            $saver = $c['config']['save.handler'];
128
129
            return new NormalizingSaver($c["saver.$saver"]);
130
        };
131
    }
132
133
    private function storageDriverPdo(Container $app)
134
    {
135
        $app['pdo'] = static function ($app) {
136
            if (!class_exists(PDO::class)) {
137
                throw new RuntimeException('Required extension ext-pdo is missing');
138
            }
139
140
            $driver = explode(':', $app['config']['pdo']['dsn'], 2)[0];
141
142
            // check the PDO driver is available
143
            if (!in_array($driver, PDO::getAvailableDrivers(), true)) {
144
                $drivers = implode(',', PDO::getAvailableDrivers()) ?: '(none)';
145
                throw new RuntimeException("Required PDO driver $driver is missing, Available drivers: $drivers");
146
            }
147
148
            $options = [
149
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
150
            ];
151
152
            if ($driver === 'mysql') {
153
                $options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET SQL_MODE=ANSI_QUOTES;';
154
            }
155
156
            return new PDO(
157
                $app['config']['pdo']['dsn'],
158
                $app['config']['pdo']['user'],
159
                $app['config']['pdo']['pass'],
160
                $options
161
            );
162
        };
163
164
        $app[PdoRepository::class] = static function ($app) {
165
            return new PdoRepository($app['pdo'], $app['config']['pdo']['table']);
166
        };
167
168
        $app['searcher.pdo'] = static function ($app) {
169
            return new PdoSearcher($app[PdoRepository::class]);
170
        };
171
172
        $app['saver.pdo'] = static function ($app) {
173
            return new Saver\PdoSaver($app[PdoRepository::class]);
174
        };
175
    }
176
177
    private function storageDriverMongoDb(Container $app)
178
    {
179
        // NOTE: db.host, db.options, db.driverOptions, db.db are @deprecated and will be removed in the future
180
        $app['mongodb.database'] = static function ($app) {
181
            $config = $app['config'];
182
            $mongodb = $config['mongodb'] ?? [];
183
184
            return $config['db.db'] ?? $mongodb['database'] ?? 'xhgui';
185
        };
186
187
        $app[MongoDB::class] = static function ($app) {
188
            $database = $app['mongodb.database'];
189
            /** @var MongoClient $client */
190
            $client = $app[MongoClient::class];
191
            $mongoDB = $client->selectDb($database);
192
            $mongoDB->results->findOne();
193
194
            return $mongoDB;
195
        };
196
197
        $app[MongoClient::class] = static function ($app) {
198
            if (!class_exists(Manager::class)) {
199
                throw new RuntimeException('Required extension ext-mongodb missing');
200
            }
201
202
            $config = $app['config'];
203
            $mongodb = $config['mongodb'] ?? [];
204
            $options = $config['db.options'] ?? $mongodb['options'] ?? [];
205
            $driverOptions = $config['db.driverOptions'] ?? $mongodb['driverOptions'] ?? [];
206
            $server = $config['db.host'] ?? sprintf('mongodb://%s:%s', $mongodb['hostname'], $mongodb['port']);
207
208
            return new MongoClient($server, $options, $driverOptions);
209
        };
210
211
        $app['searcher.mongodb'] = static function ($app) {
212
            return new MongoSearcher($app[MongoDB::class]);
213
        };
214
215
        $app['saver.mongodb'] = static function ($app) {
216
            /** @var MongoDB $mongoDB */
217
            $mongoDB = $app[MongoDB::class];
218
            /** @var MongoCollection $collection */
219
            $collection = $mongoDB->results;
0 ignored issues
show
Bug introduced by
The property results does not seem to exist in MongoDB.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
220
221
            return new Saver\MongoSaver($collection);
222
        };
223
    }
224
225
    /**
226
     * Add controllers to the DI container.
227
     */
228
    protected function _controllers()
229
    {
230
        $this['watchController'] = $this->factory(static function ($c) {
231
            return new Controller\WatchController($c['app'], $c['searcher']);
232
        });
233
234
        $this['runController'] = $this->factory(static function ($c) {
235
            return new Controller\RunController($c['app'], $c['searcher']);
236
        });
237
238
        $this['customController'] = $this->factory(static function ($c) {
239
            return new Controller\CustomController($c['app'], $c['searcher']);
240
        });
241
242
        $this['waterfallController'] = $this->factory(static function ($c) {
243
            return new Controller\WaterfallController($c['app'], $c['searcher']);
244
        });
245
246
        $this['importController'] = $this->factory(static function ($c) {
247
            return new Controller\ImportController($c['app'], $c['saver'], $c['config']['upload.token']);
248
        });
249
250
        $this['metricsController'] = $this->factory(static function ($c) {
251
            return new Controller\MetricsController($c['app'], $c['searcher']);
252
        });
253
    }
254
}
255