Completed
Branch master (1b1194)
by Ventimiglia
05:17
created

Firebase::getRules()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 3
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 31 and the first side effect is on line 12.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
declare(strict_types = 1);
3
namespace ZendFirebase;
4
5
use Interfaces\FirebaseInterface;
6
use GuzzleHttp\Client;
7
use ZendFirebase\Stream\StreamClient;
8
use Monolog\Logger;
9
use Monolog\Handler\StreamHandler;
10
use Monolog\Handler\FirePHPHandler;
11
use Monolog\Formatter\LineFormatter;
12
require 'Interfaces/FirebaseInterface.php';
13
require 'Stream/StreamClient.php';
14
15
/**
16
 * PHP7 FIREBASE LIBRARY (http://samuelventimiglia.it/)
17
 *
18
 *
19
 * @link https://github.com/Samuel18/zend_Firebase
20
 * @copyright Copyright (c) 2016-now Ventimiglia Samuel - Biasin Davide
21
 * @license BSD 3-Clause License
22
 *
23
 */
24
25
/**
26
 * This class do rest operations to firebase server
27
 *
28
 * @author ghostbyte
29
 * @package ZendFirebase
30
 */
31
class Firebase extends FirebaseResponce implements FirebaseInterface
32
{
33
34
    /**
35
     * Default Timeout
36
     *
37
     * @var integer $timeout
38
     */
39
    private $timeout = 30;
40
41
    /**
42
     * Format of datetime of logs
43
     *
44
     * @var string $dateFormatLog
45
     */
46
    private $dateFormatLog = "Y n j, g:i a";
47
48
    /**
49
     * DateTime of log filename
50
     *
51
     * @var string $dateFormatLogFilename
52
     */
53
    private static $dateFormatLogFilename;
54
55
    /**
56
     * Authentication object
57
     *
58
     * @var Config\FirebaseAuth $auth
59
     */
60
    private $auth;
61
62
    /**
63
     * Create new Client
64
     *
65
     * @var $client
66
     */
67
    private $client;
68
69
    /**
70
     * Responce from firebase
71
     *
72
     * @var mixed $response
73
     */
74
    private $response;
75
76
    /**
77
     * Last Auto-Increment saved from post operation
78
     *
79
     * @var string $lastIdStored
80
     */
81
    protected $lastIdStored = '';
82
83
    /**
84
     * Create new Firebase client object
85
     * Remember to install PHP CURL extention
86
     *
87
     * @param Config\FirebaseAuth $auth
88
     */
89
    public function __construct(\ZendFirebase\Config\FirebaseAuth $auth)
90
    {
91
        $this->checkDipendenties($auth);
92
        
93
        // store object into variable
94
        $this->auth = $auth;
95
        
96
        $this->gulleClientInit();
97
    }
98
99
    /**
100
     * Create new guzzle client
101
     */
102
    private function gulleClientInit()
103
    {
104
        
105
        /* create new client */
106
        $this->client = new Client([
107
            'base_uri' => $this->auth->getBaseURI(),
108
            'timeout' => $this->getTimeout(),
109
            'headers' => $this->getRequestHeaders()
110
        ]);
111
    }
112
113
    /**
114
     * Controll of all dipendenties
115
     *
116
     * @param \ZendFirebase\Config\FirebaseAuth $auth
117
     */
118
    private function checkDipendenties($auth)
119
    {
120
        $authMessage = 'Forget credential or is not an object.';
121
        $curlMessage = 'Extension CURL is not loaded or not installed.';
122
        
123
        // check if auth is null
124
        if (! is_object($auth) || null == $auth) {
125
            trigger_error($authMessage, E_USER_ERROR);
126
        }
127
        
128
        // check if extension is installed
129
        if (! extension_loaded('curl')) {
130
            trigger_error($curlMessage, E_USER_ERROR);
131
        }
132
    }
133
134
    /**
135
     * Return Integer of Timeout
136
     * default 30 setted 10
137
     *
138
     * @return integer $timeout
139
     */
140
    public function getTimeout(): int
141
    {
142
        return $this->timeout;
143
    }
144
145
    /**
146
     * Default timeout is 10 seconds
147
     * is is not set switch to 30
148
     *
149
     * @param integer $timeout
150
     */
151
    public function setTimeout($timeout)
152
    {
153
        $this->timeout = $timeout;
154
    }
155
156
    /**
157
     * Return string of LastIdStored generated after post command
158
     *
159
     * @return string $lastIdStored
160
     */
161
    public function getLastIdStored(): string
162
    {
163
        return $this->lastIdStored;
164
    }
165
166
    /**
167
     * Set string of LastIdStored generated after post command
168
     *
169
     * @param string $lastIdStored
170
     */
171
    public function setLastIdStored($lastIdStored)
172
    {
173
        $this->lastIdStored = $lastIdStored;
174
    }
175
176
    /**
177
     * Method for get array headers for Guzzle client
178
     *
179
     * @throws \Exception
180
     * @return array
181
     */
182
    private function getRequestHeaders(): array
183
    {
184
        $headers = [];
185
        $headers['stream'] = true;
186
        $headers['Accept'] = 'application/json';
187
        $headers['Content-Type'] = 'application/json';
188
        
189
        // check if header is an array
190
        if (! is_array($headers)) {
191
            $str = "The guzzle client headers must be an array.";
192
            throw new \Exception($str);
193
        }
194
        
195
        return $headers;
196
    }
197
198
    /**
199
     * Returns with the normalized JSON absolute path
200
     *
201
     * @param string $path
202
     * @param array $options
203
     * @return string $path
204
     */
205
    private function getJsonPath($path, $options = []): string
206
    {
207
        /* autentication token */
208
        $auth = $this->auth->getServertoken();
209
        /* returns the data in a human-readable format */
210
        $options['print'] = 'pretty';
211
        
212
        foreach ($options as $opt => $optVal) {
213
            if (\is_string($optVal)) {
214
                $options[$opt] = '"' . $optVal . '"';
215
            }
216
        }
217
        
218
        $path = ltrim($path, '/');
219
        
220
        return $path . '.json?auth=' . $auth . '&' . http_build_query($options) . '';
221
    }
222
223
    /**
224
     * DELETE - Removing Data FROM FIREBASE
225
     *
226
     * @param string $path
227
     * @param array $options
228
     *
229
     * {@inheritdoc}
230
     *
231
     * @see \Interfaces\FirebaseInterface::delete()
232
     */
233
    public function delete($path, $options = [])
234
    {
235
        $this->writeRequest('delete', $this->getJsonPath($path, $options), '');
236
    }
237
238
    /**
239
     * GET - Reading Data FROM FIREBASE
240
     *
241
     * @param string $path
242
     * @param array $options
243
     *
244
     * {@inheritdoc}
245
     *
246
     * @see \Interfaces\FirebaseInterface::get()
247
     */
248
    public function get($path, $options = [])
249
    {
250
        $this->writeRequest('get', $this->getJsonPath($path, $options), '');
251
    }
252
253
    /**
254
     * PATCH - Updating Data TO FIREBASE
255
     *
256
     * @param string $path
257
     * @param array $data
258
     * @param array $options
259
     *
260
     * {@inheritdoc}
261
     *
262
     * @see \Interfaces\FirebaseInterface::patch()
263
     */
264
    public function patch($path, array $data, $options = [])
265
    {
266
        $this->writeRequest('patch', $this->getJsonPath($path, $options), $data);
267
    }
268
269
    /**
270
     * POST - Pushing Data TO FIREBASE
271
     *
272
     * @param string $path
273
     * @param array $data
274
     * @param array $options
275
     *
276
     * {@inheritdoc}
277
     *
278
     * @see \Interfaces\FirebaseInterface::post()
279
     */
280
    public function post($path, array $data, $options = [])
281
    {
282
        $this->writeRequest('post', $this->getJsonPath($path, $options), $data);
283
    }
284
285
    /**
286
     * PUT - Writing Data TO FIREBASE
287
     *
288
     * @param string $path
289
     * @param array $data
290
     * @param array $options
291
     *
292
     * {@inheritdoc}
293
     *
294
     * @see \Interfaces\FirebaseInterface::put()
295
     */
296
    public function put($path, array $data, $options = [])
297
    {
298
        $this->writeRequest('put', $this->getJsonPath($path, $options), $data);
299
    }
300
301
    /**
302
     * RULES - Retrieve firebase rules
303
     *
304
     * @param string $path
305
     * @param array $data
306
     * @param array $options
307
     */
308
    public function getRules($path, array $data, $options = [])
309
    {
310
        $this->writeRequest('rules', $this->getJsonPath($path, $options), $data);
311
    }
312
313
    /**
314
     * Method to send request
315
     *
316
     * @param string $op
317
     * @param string $path
318
     * @param mixed $data
319
     */
320
    private function writeRequest($op, $path, $data)
321
    {
322
        $operation = \strtolower($op);
323
        
324
        switch ($operation) {
325
            case 'get':
326
                $response = $this->client->{$operation}($path);
327
                $this->response = $response->getBody()->getContents();
328
                $this->setDataFromOperation('get', $response->getStatusCode());
329
                break;
330
            case 'delete':
331
                $response = $this->client->{$operation}($path);
332
                $this->response = $response->getReasonPhrase(); // OK
333
                $this->setDataFromOperation('get', $response->getStatusCode());
334
                break;
335
            case 'post':
336
                $this->response = $this->client->{$operation}($path, [
337
                    'body' => \json_encode($data)
338
                ]);
339
                
340
                // save auto-increment id created from Firebase after post operation
341
                $this->setLastIdStored(json_decode($this->response->getBody()
342
                    ->getContents(), true)['name']);
343
                
344
                $this->setDataFromOperation($op, $this->response->getStatusCode());
345
                break;
346
            case 'rules':
347
                $operation = 'get';
348
                $bodyResponse = '';
1 ignored issue
show
Unused Code introduced by
$bodyResponse is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
349
                
350
                $response = $this->client->{$operation}($path);
351
                $bodyResponse = $response->getBody()->getContents();
352
                $this->response = $bodyResponse;
353
     
354
                $this->setDataFromOperation('get', $response->getStatusCode());
355
                break;
356
            
357
            default:
358
                $this->response = $this->client->{$operation}($path, [
359
                    'body' => \json_encode($data)
360
                ]);
361
                
362
                $this->setDataFromOperation($op, $this->response->getStatusCode());
363
                break;
364
        }
365
        
366
        $this->makeResponce();
367
    }
368
369
    /**
370
     * This function set variables after operation
371
     *
372
     * @param string $operation
373
     * @param mixed $status
374
     */
375
    private function setDataFromOperation($operation, $status)
376
    {
377
        $oP = \strtoupper($operation);
378
        
379
        $this->status = $status; // 200
380
        $this->operation = $oP;
381
    }
382
383
    /**
384
     * Start stream with server and write log in choised folder
385
     *
386
     * @param string $path
387
     * @param string $folderToStoreLog
388
     * @param integer $requestDelay
389
     * @param string $callback
390
     * @param array $options
391
     * @param boolean $print
392
     * @example $requestDelay = 3000 -> 3 seconds between get request
393
     */
394
    public function startStream($path, $folderToStoreLog, $requestDelay = 5000, $callback, $options = [], $print = true)
395
    {
396
        $url = $this->auth->getBaseURI();
397
        
398
        $client = new StreamClient($url, $requestDelay, $this->getJsonPath($path, $options));
399
        
400
        // returns generator
401
        $events = $client->getEvents();
402
        
403
        // call method for create instance of logger
404
        $logger = $this->createLogger($this->formatFolderName($folderToStoreLog));
405
        
406
        // blocks until new event arrive
407
        foreach ($events as $event) {
408
            // decode json data arrived to php array
409
            $eventData = \json_decode($event->getData(), true);
410
            
411
            // callback to return
412
            $callback($eventData, $event->getEventType());
413
            
414
            if ($print) {
415
                // anyway print data in output
416
                $this->printEventData($eventData, $event);
417
            }
418
            
419
            // write logs
420
            $this->writeEventLogs($logger, $eventData, $event, $path);
421
        }
422
    }
423
424
    /**
425
     * Print on output datas
426
     *
427
     * @param mixed $eventData
428
     * @param mixed $event
429
     */
430
    private function printEventData($eventData, $event)
431
    {
432
        // pass event to callback function
433
        print_r($eventData);
434
        print_r("EVENT TYPE: " . $event->getEventType() . PHP_EOL . PHP_EOL);
435
    }
436
437
    /**
438
     * Write log of current event
439
     *
440
     * @param Logger $logger
441
     * @param array $eventData
442
     * @param mixed $event
443
     * @param string $path
444
     */
445
    private function writeEventLogs($logger, $eventData, $event, $path)
446
    {
447
        if (! empty($eventData) || null != $eventData) {
448
            $logger->addDebug("path: {$path}", [
449
                'DATA' => $eventData,
450
                'EVENT TYPE' => $event->getEventType()
451
            ]);
452
        } else {
453
            $logger->addDebug("path: {$path}", [
454
                'EVENT TYPE' => $event->getEventType()
455
            ]);
456
        }
457
    }
458
459
    /**
460
     * Format folder name
461
     *
462
     * @param string $folderToStoreLog
463
     * @return string $folderName
464
     */
465
    private function formatFolderName($folderToStoreLog): string
466
    {
467
        /* search / in string */
468
        $folderName = substr(strrchr(trim($folderToStoreLog), "/"), 1);
469
        /* if not exsits add on path+/ */
470
        $folderName = empty($folderName) ? $folderToStoreLog . '/' : $folderToStoreLog;
471
        
472
        return $folderName;
473
    }
474
475
    /**
476
     *
477
     * Create logger instance for save stream log
478
     *
479
     * @param string $folderToStoreLog
480
     * @return Logger $logger
481
     */
482
    private function createLogger($folderToStoreLog)
483
    {
484
        // the default output format is "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"
485
        $output = "%datetime% > %level_name% > %message% %context% %extra%\n";
486
        // finally, create a formatter
487
        $formatter = new LineFormatter($output, $this->dateFormatLog);
488
        self::$dateFormatLogFilename = date("Y-m-d_H:i:s");
489
        // Create the logger
490
        $logger = new Logger('stream_logger');
491
        
492
        // Now add some handlers
493
        $stream = new StreamHandler(trim($folderToStoreLog) . self::$dateFormatLogFilename . ".log", Logger::DEBUG);
494
        
495
        $stream->setFormatter($formatter);
496
        $logger->pushHandler($stream);
497
        $logger->pushHandler(new FirePHPHandler());
498
        
499
        // You can now use your logger
500
        $logger->addInfo('Stream logger is ready...');
501
        return $logger;
502
    }
503
504
    /**
505
     * This method return the responce from firebase
506
     *
507
     * @example set and validate data passed
508
     */
509
    private function makeResponce()
510
    {
511
        $jsonData = [];
512
        if ($this->operation === 'GET') {
513
            $jsonData = json_decode($this->response, true);
514
            if (empty($jsonData)) {
515
                $jsonData[] = '204 No Content';
516
            } else {
517
                $jsonData = json_decode($this->response, true);
518
            }
519
        } else {
520
            $jsonData[] = 'Success';
521
        }
522
        
523
        /* Set data after operations */
524
        $this->setOperation($this->operation);
525
        $this->setStatus($this->status);
526
        
527
        $this->setFirebaseData($jsonData);
528
        $this->validateResponce();
529
    }
530
531
    /**
532
     * Remove object from memory
533
     */
534
    public function __destruct()
535
    {}
536
}
537