Completed
Push — 2.0 ( 143803...4e64fa )
by grégoire
08:42 queued 04:22
created

Session::getClientUsingPooler()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

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