Completed
Push — master ( 15062c...e729ea )
by Elan
19s queued 11s
created

ServiceContainer::controllers()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 26

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 26
rs 9.504
c 0
b 0
f 0
cc 1
nc 1
nop 0
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\Saver\NormalizingSaver;
17
use XHGui\Searcher\MongoSearcher;
18
use XHGui\Searcher\PdoSearcher;
19
use XHGui\ServiceProvider\ConfigProvider;
20
use XHGui\ServiceProvider\RouteProvider;
21
use XHGui\Twig\TwigExtension;
22
23
class ServiceContainer extends Container
24
{
25
    /** @var self */
26
    protected static $_instance;
27
28
    /**
29
     * @return self
30
     */
31
    public static function instance()
32
    {
33
        if (empty(static::$_instance)) {
34
            static::$_instance = new self();
35
            static::$_instance->boot();
36
        }
37
38
        return static::$_instance;
39
    }
40
41
    public function __construct()
42
    {
43
        parent::__construct();
44
        $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...
45
        $this->register(new ConfigProvider());
46
        $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...
47
        $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...
48
        $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...
49
        $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...
50
        $this->controllers();
51
    }
52
53
    public function boot(): void
54
    {
55
        $this->register(new RouteProvider());
56
    }
57
58
    private function setupPaths(self $app): void
59
    {
60
        $app['app.dir'] = dirname(__DIR__);
61
        $app['app.template_dir'] = dirname(__DIR__) . '/templates';
62
        $app['app.config_dir'] = dirname(__DIR__) . '/config';
63
        $app['app.cache_dir'] = static function ($c) {
64
            return $c['config']['cache'] ?? dirname(__DIR__) . '/cache';
65
        };
66
    }
67
68
    // Create the Slim app.
69
    private function slimApp(): void
70
    {
71
        $this['view'] = static function ($c) {
72
            // Configure Twig view for slim
73
            $view = new Twig();
74
75
            $view->twigTemplateDirs = [
76
                $c['app.template_dir'],
77
            ];
78
            $view->parserOptions = [
79
                'charset' => 'utf-8',
80
                'cache' => $c['app.cache_dir'],
81
                'auto_reload' => true,
82
                'strict_variables' => false,
83
                'autoescape' => 'html',
84
            ];
85
86
            return $view;
87
        };
88
89
        $this['app'] = static function ($c) {
90
            if ($c['config']['timezone']) {
91
                date_default_timezone_set($c['config']['timezone']);
92
            }
93
94
            $app = new App($c['config']);
95
96
            // Enable cookie based sessions
97
            $app->add(new SessionCookie([
98
                'httponly' => true,
99
            ]));
100
101
            $view = $c['view'];
102
            $view->parserExtensions = [
103
                new TwigExtension($app),
104
            ];
105
            $app->view($view);
106
107
            return $app;
108
        };
109
    }
110
111
    /**
112
     * Add common service objects to the container.
113
     */
114
    private function services(): void
115
    {
116
        $this['searcher'] = static function ($c) {
117
            $saver = $c['config']['save.handler'];
118
119
            return $c["searcher.$saver"];
120
        };
121
122
        $this['saver'] = static function ($c) {
123
            $saver = $c['config']['save.handler'];
124
125
            return new NormalizingSaver($c["saver.$saver"]);
126
        };
127
    }
128
129
    private function storageDriverPdo(Container $app): void
130
    {
131
        $app['pdo'] = static function ($app) {
132
            if (!class_exists(PDO::class)) {
133
                throw new RuntimeException('Required extension ext-pdo is missing');
134
            }
135
136
            $driver = explode(':', $app['config']['pdo']['dsn'], 2)[0];
137
138
            // check the PDO driver is available
139
            if (!in_array($driver, PDO::getAvailableDrivers(), true)) {
140
                $drivers = implode(',', PDO::getAvailableDrivers()) ?: '(none)';
141
                throw new RuntimeException("Required PDO driver $driver is missing, Available drivers: $drivers");
142
            }
143
144
            $options = [
145
                PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
146
            ];
147
148
            if ($driver === 'mysql') {
149
                $options[PDO::MYSQL_ATTR_INIT_COMMAND] = 'SET SQL_MODE=ANSI_QUOTES;';
150
            }
151
152
            return new PDO(
153
                $app['config']['pdo']['dsn'],
154
                $app['config']['pdo']['user'],
155
                $app['config']['pdo']['pass'],
156
                $options
157
            );
158
        };
159
160
        $app[PdoRepository::class] = static function ($app) {
161
            return new PdoRepository($app['pdo'], $app['config']['pdo']['table']);
162
        };
163
164
        $app['searcher.pdo'] = static function ($app) {
165
            return new PdoSearcher($app[PdoRepository::class]);
166
        };
167
168
        $app['saver.pdo'] = static function ($app) {
169
            return new Saver\PdoSaver($app[PdoRepository::class]);
170
        };
171
    }
172
173
    private function storageDriverMongoDb(Container $app): void
174
    {
175
        // NOTE: db.host, db.options, db.driverOptions, db.db are @deprecated and will be removed in the future
176
        $app['mongodb.database'] = static function ($app) {
177
            $config = $app['config'];
178
            $mongodb = $config['mongodb'] ?? [];
179
180
            return $config['db.db'] ?? $mongodb['database'] ?? 'xhgui';
181
        };
182
183
        $app[MongoDB::class] = static function ($app) {
184
            $database = $app['mongodb.database'];
185
            /** @var MongoClient $client */
186
            $client = $app[MongoClient::class];
187
            $mongoDB = $client->selectDb($database);
188
            $mongoDB->results->findOne();
189
190
            return $mongoDB;
191
        };
192
193
        $app[MongoClient::class] = static function ($app) {
194
            if (!class_exists(Manager::class)) {
195
                throw new RuntimeException('Required extension ext-mongodb missing');
196
            }
197
198
            $config = $app['config'];
199
            $mongodb = $config['mongodb'] ?? [];
200
            $options = $config['db.options'] ?? $mongodb['options'] ?? [];
201
            $driverOptions = $config['db.driverOptions'] ?? $mongodb['driverOptions'] ?? [];
202
            $server = $config['db.host'] ?? sprintf('mongodb://%s:%s', $mongodb['hostname'], $mongodb['port']);
203
204
            return new MongoClient($server, $options, $driverOptions);
205
        };
206
207
        $app['searcher.mongodb'] = static function ($app) {
208
            return new MongoSearcher($app[MongoDB::class]);
209
        };
210
211
        $app['saver.mongodb'] = static function ($app) {
212
            /** @var MongoDB $mongoDB */
213
            $mongoDB = $app[MongoDB::class];
214
            /** @var MongoCollection $collection */
215
            $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...
216
217
            return new Saver\MongoSaver($collection);
218
        };
219
    }
220
221
    /**
222
     * Add controllers to the DI container.
223
     */
224
    private function controllers(): void
225
    {
226
        $this['watchController'] = $this->factory(static function ($c) {
227
            return new Controller\WatchController($c['app'], $c['searcher']);
228
        });
229
230
        $this['runController'] = $this->factory(static function ($c) {
231
            return new Controller\RunController($c['app'], $c['searcher']);
232
        });
233
234
        $this['customController'] = $this->factory(static function ($c) {
235
            return new Controller\CustomController($c['app'], $c['searcher']);
236
        });
237
238
        $this['waterfallController'] = $this->factory(static function ($c) {
239
            return new Controller\WaterfallController($c['app'], $c['searcher']);
240
        });
241
242
        $this['importController'] = $this->factory(static function ($c) {
243
            return new Controller\ImportController($c['app'], $c['saver'], $c['config']['upload.token']);
244
        });
245
246
        $this['metricsController'] = $this->factory(static function ($c) {
247
            return new Controller\MetricsController($c['app'], $c['searcher']);
248
        });
249
    }
250
}
251