Session::hasPoolerForType()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
/*
3
 * This file is part of the Pomm's Foundation package.
4
 *
5
 * (c) 2014 - 2017 Grégoire HUBERT <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 */
10
namespace PommProject\Foundation\Session;
11
12
use PommProject\Foundation\Inflector;
13
use PommProject\Foundation\Client\Client;
14
use PommProject\Foundation\Client\ClientHolder;
15
use PommProject\Foundation\Client\ClientInterface;
16
use PommProject\Foundation\Client\ClientPoolerInterface;
17
use PommProject\Foundation\Exception\FoundationException;
18
use Psr\Log\LoggerAwareInterface;
19
use Psr\Log\LoggerAwareTrait;
20
use Psr\Log\LoggerInterface;
21
22
/**
23
 * Session
24
 *
25
 * Public API to share the database connection. IO are shared amongst
26
 * clients which are stored in a ClientHolder.
27
 *
28
 * @package     Foundation
29
 * @copyright   2014 - 2017 Grégoire HUBERT
30
 * @author      Grégoire HUBERT
31
 * @license     X11 {@link http://opensource.org/licenses/mit-license.php}
32
 * @see         LoggerAwareInterface
33
 */
34
class Session implements LoggerAwareInterface
35
{
36
    protected $connection;
37
    protected $client_holder;
38
    protected $client_poolers = [];
39
    protected $stamp;
40
    protected $is_shutdown = false;
41
42
    use LoggerAwareTrait;
43
44
    /**
45
     * __construct
46
     *
47
     * Constructor.
48
     * In order to create a physical connection to the database, it requires a
49
     * 'dsn' parameter from the ParameterHolder.
50
     *
51
     * @param   Connection       $connection
52
     * @param   ClientHolder     $client_holder
53
     * @param   string           $stamp
54
     */
55
    public function __construct(
56
        Connection      $connection,
57
        ClientHolder    $client_holder = null,
58
        $stamp = null
59
    ) {
60
        $this->connection    = $connection;
61
        $this->client_holder = $client_holder === null
62
            ? new ClientHolder
63
            : $client_holder
64
            ;
65
        $this->stamp = $stamp;
66
    }
67
68
    /**
69
     * __destruct
70
     *
71
     * A short description here
72
     *
73
     * @return null
74
     */
75
    public function __destruct()
76
    {
77
        if (!$this->is_shutdown) {
78
            $this->shutdown();
79
        }
80
    }
81
82
    /**
83
     * shutdown
84
     *
85
     * Gently shutdown all clients when the Session is getting down prior to
86
     * connection termination.
87
     *
88
     * @return  null
89
     */
90
    public function shutdown()
91
    {
92
        $exceptions = $this->client_holder->shutdown();
93
94
        if ($this->hasLogger()) {
95
            foreach ($exceptions as $exception) {
96
                printf(
97
                    "Exception caught during shutdown: %s\n",
98
                    (string) $exception
99
                );
100
            }
101
102
            $this->logger = null;
103
        }
104
105
        $this->client_poolers = [];
106
        $this->connection->close();
107
        $this->is_shutdown = true;
108
    }
109
110
    /**
111
     * getStamp
112
     *
113
     * Return the session's stamp if any
114
     *
115
     * @return  string|null
116
     */
117
    public function getStamp()
118
    {
119
        return $this->stamp === null ? null : (string) $this->stamp;
120
    }
121
122
    /**
123
     * getLogger
124
     *
125
     * Return the logger if any.
126
     *
127
     * @return  LoggerInterface|null
128
     */
129
    public function getLogger()
130
    {
131
        return $this->logger;
132
    }
133
134
    /**
135
     * hasLogger
136
     *
137
     * Return true if a logger is set.
138
     *
139
     * @return  bool
140
     */
141
    public function hasLogger()
142
    {
143
        return (bool) ($this->logger !== null);
144
    }
145
146
    /**
147
     * getConnection
148
     *
149
     * Return the database connection.
150
     *
151
     * @return  Connection
152
     */
153
    public function getConnection()
154
    {
155
        return $this->connection;
156
    }
157
158
    /**
159
     * registerClient
160
     *
161
     * Initialize a connection client with context and register it in the
162
     * client holder.
163
     *
164
     * @param   ClientInterface $client
165
     * @return  Session $this
166
     */
167
    public function registerClient(ClientInterface $client)
168
    {
169
        $client->initialize($this);
170
        $this->client_holder->add($client);
171
        $this->hasLogger() && $this->getLogger()->debug(
172
            "Pomm: Registering new client",
173
            [
174
                'type' => $client->getClientType(),
175
                'identifier' => $client->getClientIdentifier(),
176
            ]
177
        );
178
179
        return $this;
180
    }
181
182
    /**
183
     * getClient
184
     *
185
     * Return a Client from its type and identifier.
186
     *
187
     * @param   string $type
188
     * @param   string $identifier
189
     * @return  Client or null if not found.
190
     */
191
    public function getClient($type, $identifier)
192
    {
193
        return $this->client_holder->get($type, $identifier);
194
    }
195
196
    /**
197
     * hasClient
198
     *
199
     * Tell if a client exist or not.
200
     *
201
     * @param   string $type
202
     * @param   string $name
203
     * @return  bool
204
     */
205
    public function hasClient($type, $name)
206
    {
207
        return $this->client_holder->has($type, $name);
208
    }
209
210
    /**
211
     * registerClientPooler
212
     *
213
     * Add or replace a Client pooler for the specified type.
214
     *
215
     * @param   ClientPoolerInterface $client_pooler
216
     * @return  Session               $this
217
     */
218
    public function registerClientPooler(ClientPoolerInterface $client_pooler)
219
    {
220
        if ($client_pooler->getPoolerType() == null) {
221
            throw new \InvalidArgumentException("Can not register a pooler for the empty type.");
222
        }
223
224
        $client_pooler->register($this);
225
        $this->client_poolers[$client_pooler->getPoolerType()] = $client_pooler;
226
        $this->hasLogger()
227
            && $this->getLogger()
228
            ->debug(
229
                "Pomm: Registering new client pooler.",
230
                ['type' => $client_pooler->getPoolerType()]
231
            );
232
233
        return $this;
234
    }
235
236
    /**
237
     * hasPoolerForType
238
     *
239
     * Tell if a pooler exist or not.
240
     *
241
     * @param   string  $type
242
     * @return  bool
243
     */
244
    public function hasPoolerForType($type)
245
    {
246
        return (bool) (isset($this->client_poolers[$type]));
247
    }
248
249
    /**
250
     * getPoolerForType
251
     *
252
     * Get the registered for the given type.
253
     *
254
     * @param   string              $type
255
     * @throws  FoundationException if pooler does not exist
256
     * @return  ClientPoolerInterface
257
     */
258
    public function getPoolerForType($type)
259
    {
260
        if (!$this->hasPoolerForType($type)) {
261
            $error_message = <<<ERROR
262
No pooler registered for type '%s'. Poolers available: {%s}.
263
If the pooler you are asking for is not listed there, maybe you have not used
264
the correct session builder. Use the "class:session_builder" parameter in the
265
configuration to associate each session with a session builder. A good practice
266
is to define your own project's session builders.
267
ERROR;
268
            if ($this->is_shutdown) {
269
                $error_message = 'There are no poolers in the session because it is shutdown.';
270
            }
271
272
            throw new FoundationException(
273
                sprintf(
274
                    $error_message,
275
                    $type,
276
                    join(', ', $this->getRegisterPoolersNames())
277
                )
278
            );
279
        }
280
281
        return $this->client_poolers[$type];
282
    }
283
284
    /**
285
     * getAllClientForType
286
     *
287
     * Return all instances of clients for a given type.
288
     *
289
     * @param   string $type
290
     * @return  ClientInterface
291
     */
292
    public function getAllClientForType($type)
293
    {
294
        return $this->client_holder->getAllFor($type);
295
    }
296
297
    /**
298
     * getClientUsingPooler
299
     *
300
     * Summon a pooler to retrieve a client. If the pooler does not exist, a
301
     * FoundationException is thrown.
302
     *
303
     * @param   string          $type
304
     * @param   string          $identifier
305
     * @return  ClientInterface
306
     */
307
    public function getClientUsingPooler($type, $identifier)
308
    {
309
        return $this->getPoolerForType($type)->getClient($identifier);
310
    }
311
312
    /**
313
     * __call
314
     *
315
     * Create handy methods to access clients through a pooler.
316
     *
317
     * @param   string                   $method
318
     * @param   array                    $arguments
319
     * @throws  \BadFunctionCallException if unknown method
320
     * @throws  FoundationException      if no poolers found
321
     * @return  ClientInterface
322
     */
323
    public function __call($method, $arguments)
324
    {
325
        if (!preg_match('/get([A-Z][A-Za-z]+)/', $method, $matches)) {
326
            throw new \BadFunctionCallException(sprintf("Unknown method 'Session::%s()'.", $method));
327
        }
328
329
        return $this->getClientUsingPooler(
330
            Inflector::underscore($matches[1]),
331
            count($arguments) > 0 ? $arguments[0] : null
332
        );
333
    }
334
335
    /**
336
     * getRegisterPoolersNames
337
     *
338
     * Useful to test & debug.
339
     *
340
     * @return  array
341
     */
342
    public function getRegisterPoolersNames()
343
    {
344
        return array_keys($this->client_poolers);
345
    }
346
}
347