Completed
Push — master ( b7f9bf...48ba4b )
by Lars
02:40
created

Cache::calculateStoreKey()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 10
ccs 5
cts 5
cp 1
rs 9.9332
c 0
b 0
f 0
cc 2
nc 2
nop 1
crap 2
1
<?php
2
3
declare(strict_types=1);
4
5
namespace voku\cache;
6
7
use voku\cache\Exception\InvalidArgumentException;
8
9
/**
10
 * Cache: global-cache class
11
 *
12
 * can use different cache-adapter:
13
 * - Redis
14
 * - Memcache / Memcached
15
 * - APC / APCu
16
 * - Xcache
17
 * - Array
18
 * - File / OpCache
19
 *
20
 * @package   voku\cache
21
 */
22
class Cache implements iCache
23
{
24
25
  /**
26
   * @var iAdapter
27
   */
28
  protected $adapter;
29
30
  /**
31
   * @var iSerializer
32
   */
33
  protected $serializer;
34
35
  /**
36
   * @var string
37
   */
38
  protected $prefix = '';
39
40
  /**
41
   * @var bool
42
   */
43
  protected $isReady = false;
44
45
  /**
46
   * @var bool
47
   */
48
  protected $isActive = true;
49
50
  /**
51
   * @var bool
52
   */
53
  protected $useCheckForDev;
54
55
  /**
56
   * @var bool
57
   */
58
  protected $useCheckForAdminSession;
59
60
  /**
61
   * @var bool
62
   */
63
  protected $useCheckForServerIpIsClientIp;
64
65
  /**
66
   * @var string
67
   */
68
  protected $disableCacheGetParameter;
69
70
  /**
71
   * @var bool
72
   */
73
  protected $isAdminSession;
74
75
  /**
76
   * @var array
77
   */
78
  protected static $STATIC_CACHE = [];
79
80
  /**
81
   * @var array
82
   */
83
  protected static $STATIC_CACHE_EXPIRE = [];
84
85
  /**
86
   * @var array
87
   */
88
  protected static $STATIC_CACHE_COUNTER = [];
89
90
  /**
91
   * @var int
92
   */
93
  protected $staticCacheHitCounter = 10;
94
95
  /**
96
   * __construct
97
   *
98
   * @param null|iAdapter    $adapter
99
   * @param null|iSerializer $serializer
100
   * @param bool             $checkForUsage                 <p>admin-session || server-ip == client-ip || check for
101
   *                                                        dev</p>
102
   * @param bool             $cacheEnabled                  <p>false will disable the cache (use it e.g. for global
103
   *                                                        settings)</p>
104
   * @param string|bool      $isAdminSession                <p>set a admin-id, if the user is a admin (so we can
105
   *                                                        disable cache for this user)
106
   * @param bool             $useCheckForAdminSession       <p>use $isAdminSession flag or not</p>
107
   * @param bool             $useCheckForDev                <p>use checkForDev() or not</p>
108
   * @param bool             $useCheckForServerIpIsClientIp <p>use check for server-ip == client-ip or not</p>
109
   * @param string           $disableCacheGetParameter      <p>set the _GET parameter for disabling the cache, disable this check via empty string</p>
110
   */
111 65
  public function __construct(
112
      iAdapter $adapter = null,
113
      iSerializer $serializer = null,
114
      bool $checkForUsage = true,
115
      bool $cacheEnabled = true,
116
      bool $isAdminSession = false,
117
      bool $useCheckForDev = true,
118
      bool $useCheckForAdminSession = true,
119
      bool $useCheckForServerIpIsClientIp = true,
120
      string $disableCacheGetParameter = 'testWithoutCache'
121
  )
122
  {
123 65
    $this->isAdminSession = $isAdminSession;
0 ignored issues
show
Documentation Bug introduced by
It seems like $isAdminSession can also be of type string. However, the property $isAdminSession is declared as type boolean. Maybe add an additional type check?

Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.

For example, imagine you have a variable $accountId that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to the id property of an instance of the Account class. This class holds a proper account, so the id value must no longer be false.

Either this assignment is in error or a type check should be added for that assignment.

class Id
{
    public $id;

    public function __construct($id)
    {
        $this->id = $id;
    }

}

class Account
{
    /** @var  Id $id */
    public $id;
}

$account_id = false;

if (starsAreRight()) {
    $account_id = new Id(42);
}

$account = new Account();
if ($account instanceof Id)
{
    $account->id = $account_id;
}
Loading history...
124
125 65
    $this->useCheckForDev = $useCheckForDev;
126 65
    $this->useCheckForAdminSession = $useCheckForAdminSession;
127 65
    $this->useCheckForServerIpIsClientIp = $useCheckForServerIpIsClientIp;
128
129 65
    $this->disableCacheGetParameter = $disableCacheGetParameter;
130
131
    // First check if the cache is active at all.
132 65
    $this->isActive = $cacheEnabled;
133
    if (
134 65
        $this->isActive === true
135
        &&
136 65
        $checkForUsage === true
137
    ) {
138
      $this->setActive($this->isCacheActiveForTheCurrentUser());
139
    }
140
141
    // If the cache is active, then try to auto-connect to the best possible cache-system.
142 65
    if ($this->isActive === true) {
143
144 65
      $this->setPrefix($this->getTheDefaultPrefix());
145
146 65
      if ($adapter === null) {
147
        $adapter = $this->autoConnectToAvailableCacheSystem();
148
      }
149
150
      // INFO: Memcache(d) has his own "serializer", so don't use it twice
151 65
      if (!\is_object($serializer) && $serializer === null) {
152
        if (
153
            $adapter instanceof AdapterMemcached
154
            ||
155
            $adapter instanceof AdapterMemcache
156
        ) {
157
          $serializer = new SerializerNo();
158
        } else {
159
          // set default serializer
160
          $serializer = new SerializerIgbinary();
161
        }
162
      }
163
    }
164
165
    // Final checks ...
166
    if (
167 65
        $serializer !== null
168
        &&
169 65
        $adapter !== null
170
    ) {
171 65
      $this->setCacheIsReady(true);
172
173 65
      $this->adapter = $adapter;
174 65
      $this->serializer = $serializer;
175
    }
176 65
  }
177
178
  /**
179
   * enable / disable the cache
180
   *
181
   * @param bool $isActive
182
   */
183
  public function setActive(bool $isActive)
184
  {
185
    $this->isActive = $isActive;
186
  }
187
188
  /**
189
   * check if the current use is a admin || dev || server == client
190
   *
191
   * @return bool
192
   */
193
  public function isCacheActiveForTheCurrentUser(): bool
194
  {
195
    $active = true;
196
197
    // test the cache, with this GET-parameter
198
    if ($this->disableCacheGetParameter) {
199
      $testCache = isset($_GET[$this->disableCacheGetParameter]) ? (int)$_GET[$this->disableCacheGetParameter] : 0;
200
    } else {
201
      $testCache = 0;
202
    }
203
204
    if ($testCache != 1) {
205
      if (
206
        // admin session is active
207
          (
208
              $this->useCheckForAdminSession
209
              &&
210
              $this->isAdminSession
211
          )
212
          ||
213
          // server == client
214
          (
215
              $this->useCheckForServerIpIsClientIp === true
216
              &&
217
              isset($_SERVER['SERVER_ADDR'])
218
              &&
219
              $_SERVER['SERVER_ADDR'] == $this->getClientIp()
220
          )
221
          ||
222
          // user is a dev
223
          (
224
              $this->useCheckForDev === true
225
              &&
226
              $this->checkForDev() === true
227
          )
228
      ) {
229
        $active = false;
230
      }
231
    }
232
233
    return $active;
234
  }
235
236
  /**
237
   * returns the IP address of the client
238
   *
239
   * @param bool $trust_proxy_headers     <p>
240
   *                                      Whether or not to trust the
241
   *                                      proxy headers HTTP_CLIENT_IP
242
   *                                      and HTTP_X_FORWARDED_FOR. ONLY
243
   *                                      use if your $_SERVER is behind a
244
   *                                      proxy that sets these values
245
   *                                      </p>
246
   *
247
   * @return string
248
   */
249
  protected function getClientIp(bool $trust_proxy_headers = false): string
250
  {
251
    $remoteAddr = $_SERVER['REMOTE_ADDR'] ?? 'NO_REMOTE_ADDR';
252
253
    if ($trust_proxy_headers) {
254
      return $remoteAddr;
255
    }
256
257
    if (!empty($_SERVER['HTTP_CLIENT_IP'])) {
258
      $ip = $_SERVER['HTTP_CLIENT_IP'];
259
    } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
260
      $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
261
    } else {
262
      $ip = $remoteAddr;
263
    }
264
265
    return $ip;
266
  }
267
268
  /**
269
   * Check for local developer.
270
   *
271
   * @return bool
272
   */
273
  protected function checkForDev(): bool
274
  {
275
    $return = false;
276
277
    if (\function_exists('checkForDev')) {
278
      $return = checkForDev();
279
    } else {
280
281
      // for testing with dev-address
282
      $noDev = isset($_GET['noDev']) ? (int)$_GET['noDev'] : 0;
283
      $remoteAddr = $_SERVER['REMOTE_ADDR'] ?? 'NO_REMOTE_ADDR';
284
285
      if (
286
          $noDev != 1
287
          &&
288
          (
289
              $remoteAddr === '127.0.0.1'
290
              ||
291
              $remoteAddr === '::1'
292
              ||
293
              PHP_SAPI === 'cli'
294
          )
295
      ) {
296
        $return = true;
297
      }
298
    }
299
300
    return $return;
301
  }
302
303
  /**
304
   * Set the default-prefix via "SERVER"-var + "SESSION"-language.
305
   */
306 65
  protected function getTheDefaultPrefix(): string
307
  {
308 65
    return ($_SERVER['SERVER_NAME'] ?? '') . '_' .
309 65
           ($_SERVER['THEME'] ?? '') . '_' .
310 65
           ($_SERVER['STAGE'] ?? '') . '_' .
311 65
           ($_SESSION['language'] ?? '') . '_' .
312 65
           ($_SESSION['language_extra'] ?? '');
313
  }
314
315
  /**
316
   * Auto-connect to the available cache-system on the server.
317
   *
318
   * @return iAdapter
319
   */
320
  protected function autoConnectToAvailableCacheSystem(): iAdapter
321
  {
322
    static $adapterCache;
323
324
    if (\is_object($adapterCache) && $adapterCache instanceof iAdapter) {
325
      return $adapterCache;
326
    }
327
328
    $memcached = null;
329
    $isMemcachedAvailable = false;
330
    if (\extension_loaded('memcached')) {
331
      /** @noinspection PhpComposerExtensionStubsInspection */
332
      $memcached = new \Memcached();
333
      /** @noinspection PhpUsageOfSilenceOperatorInspection */
334
      $isMemcachedAvailable = @$memcached->addServer('127.0.0.1', 11211);
335
    }
336
337
    if ($isMemcachedAvailable === false) {
338
      $memcached = null;
339
    }
340
341
    $adapterMemcached = new AdapterMemcached($memcached);
342
    if ($adapterMemcached->installed() === true) {
343
344
      // -------------------------------------------------------------
345
      // "Memcached"
346
      // -------------------------------------------------------------
347
      $adapter = $adapterMemcached;
348
349
    } else {
350
351
      $memcache = null;
352
      $isMemcacheAvailable = false;
353
      /** @noinspection ClassConstantCanBeUsedInspection */
354
      if (\class_exists('\Memcache')) {
355
        /** @noinspection PhpComposerExtensionStubsInspection */
356
        $memcache = new \Memcache;
357
        /** @noinspection PhpUsageOfSilenceOperatorInspection */
358
        $isMemcacheAvailable = @$memcache->connect('127.0.0.1', 11211);
359
      }
360
361
      if ($isMemcacheAvailable === false) {
362
        $memcache = null;
363
      }
364
365
      $adapterMemcache = new AdapterMemcache($memcache);
366
      if ($adapterMemcache->installed() === true) {
367
368
        // -------------------------------------------------------------
369
        // "Memcache"
370
        // -------------------------------------------------------------
371
        $adapter = $adapterMemcache;
372
373
      } else {
374
375
        $redis = null;
376
        $isRedisAvailable = false;
377
        if (
378
            \extension_loaded('redis')
379
            &&
380
            \class_exists('\Predis\Client')
381
        ) {
382
          /** @noinspection PhpUndefinedNamespaceInspection */
383
          /** @noinspection PhpUndefinedClassInspection */
384
          $redis = new \Predis\Client(
385
              [
386
                  'scheme'  => 'tcp',
387
                  'host'    => '127.0.0.1',
388
                  'port'    => 6379,
389
                  'timeout' => '2.0',
390
              ]
391
          );
392
          try {
393
            /** @noinspection PhpUndefinedMethodInspection */
394
            $redis->connect();
395
            /** @noinspection PhpUndefinedMethodInspection */
396
            $isRedisAvailable = $redis->getConnection()->isConnected();
397
          } catch (\Exception $e) {
398
            // nothing
399
          }
400
        }
401
402
        if ($isRedisAvailable === false) {
403
          $redis = null;
404
        }
405
406
        $adapterRedis = new AdapterPredis($redis);
407
        if ($adapterRedis->installed() === true) {
408
409
          // -------------------------------------------------------------
410
          // Redis
411
          // -------------------------------------------------------------
412
          $adapter = $adapterRedis;
413
414
        } else {
415
416
          $adapterXcache = new AdapterXcache();
417
          if ($adapterXcache->installed() === true) {
418
419
            // -------------------------------------------------------------
420
            // "Xcache"
421
            // -------------------------------------------------------------
422
            $adapter = $adapterXcache;
423
424
          } else {
425
426
            $adapterApcu = new AdapterApcu();
427
            if ($adapterApcu->installed() === true) {
428
429
              // -------------------------------------------------------------
430
              // "APCu"
431
              // -------------------------------------------------------------
432
              $adapter = $adapterApcu;
433
434
            } else {
435
436
              $adapterApc = new AdapterApc();
437
              if ($adapterApc->installed() === true) {
438
439
                // -------------------------------------------------------------
440
                // "APC"
441
                // -------------------------------------------------------------
442
                $adapter = $adapterApc;
443
444
              } else {
445
446
                $adapterObCache = new AdapterOpCache();
447
                if ($adapterObCache->installed() === true) {
448
449
                  // -------------------------------------------------------------
450
                  // OpCache (via PHP-files)
451
                  // -------------------------------------------------------------
452
                  $adapter = $adapterObCache;
453
454
                } else {
455
456
                  // -------------------------------------------------------------
457
                  // Static-PHP-Cache
458
                  // -------------------------------------------------------------
459
                  $adapter = new AdapterArray();
460
                }
461
              }
462
            }
463
          }
464
        }
465
      }
466
    }
467
468
    // save to static cache
469
    $adapterCache = $adapter;
470
471
    return $adapter;
472
  }
473
474
  /**
475
   * Set "isReady" state.
476
   *
477
   * @param bool $isReady
478
   */
479 65
  protected function setCacheIsReady(bool $isReady)
480
  {
481 65
    $this->isReady = $isReady;
482 65
  }
483
484
  /**
485
   * Get the "isReady" state.
486
   *
487
   * @return bool
488
   */
489 5
  public function getCacheIsReady(): bool
490
  {
491 5
    return $this->isReady;
492
  }
493
494
  /**
495
   * Get cached-item by key.
496
   *
497
   * @param string $key
498
   * @param int    $forceStaticCacheHitCounter
499
   *
500
   * @return mixed
501
   */
502 31
  public function getItem(string $key, int $forceStaticCacheHitCounter = 0)
503
  {
504 31
    if (!$this->adapter instanceof iAdapter) {
505
      return null;
506
    }
507
508 31
    $storeKey = $this->calculateStoreKey($key);
509
510
    // check if we already using static-cache
511 31
    $useStaticCache = true;
512 31
    if ($this->adapter instanceof AdapterArray) {
513 6
      $useStaticCache = false;
514
    }
515
516 31
    if (!isset(self::$STATIC_CACHE_COUNTER[$storeKey])) {
517 24
      self::$STATIC_CACHE_COUNTER[$storeKey] = 0;
518
    }
519
520
    // get from static-cache
521
    if (
522 31
        $useStaticCache === true
523
        &&
524 31
        $this->checkForStaticCache($storeKey) === true
525
    ) {
526 8
      return self::$STATIC_CACHE[$storeKey];
527
    }
528
529 29
    $serialized = $this->adapter->get($storeKey);
530 29
    $value = $serialized ? $this->serializer->unserialize($serialized) : null;
531
532 29
    self::$STATIC_CACHE_COUNTER[$storeKey]++;
533
534
    // save into static-cache if needed
535
    if (
536 29
        $useStaticCache === true
537
        &&
538
        (
539
            (
540 23
                $forceStaticCacheHitCounter !== 0
541
                &&
542
                self::$STATIC_CACHE_COUNTER[$storeKey] >= $forceStaticCacheHitCounter
543
            )
544
            ||
545
            (
546 23
                $this->staticCacheHitCounter !== 0
547
                &&
548 29
                self::$STATIC_CACHE_COUNTER[$storeKey] >= $this->staticCacheHitCounter
549
            )
550
        )
551
    ) {
552 9
      self::$STATIC_CACHE[$storeKey] = $value;
553
    }
554
555 29
    return $value;
556
  }
557
558
  /**
559
   * Calculate store-key (prefix + $rawKey).
560
   *
561
   * @param string $rawKey
562
   *
563
   * @return string
564
   */
565 53
  protected function calculateStoreKey(string $rawKey): string
566
  {
567 53
    $str = $this->getPrefix() . $rawKey;
568
569 53
    if ($this->adapter instanceof AdapterFileAbstract) {
570 24
      $str = $this->cleanStoreKey($str);
571
    }
572
573 53
    return $str;
574
  }
575
576
  /**
577
   * Clean store-key (required e.g. for the "File"-Adapter).
578
   *
579
   * @param string $str
580
   *
581
   * @return string
582
   */
583 24
  protected function cleanStoreKey(string $str): string
584
  {
585 24
    return \md5($str);
586
  }
587
588
  /**
589
   * Get the prefix.
590
   *
591
   * @return string
592
   */
593 53
  public function getPrefix(): string
594
  {
595 53
    return $this->prefix;
596
  }
597
598
  /**
599
   * !!! Set the prefix. !!!
600
   *
601
   * WARNING: Do not use if you don't know what you do. Because this will overwrite the default prefix.
602
   *
603
   * @param string $prefix
604
   */
605 65
  public function setPrefix(string $prefix)
606
  {
607 65
    $this->prefix = $prefix;
608 65
  }
609
610
  /**
611
   * Get the current value, when the static cache is used.
612
   *
613
   * @return int
614
   */
615
  public function getStaticCacheHitCounter(): int
616
  {
617
    return $this->staticCacheHitCounter;
618
  }
619
620
  /**
621
   * Set the static-hit-counter: Who often do we hit the cache, before we use static cache?
622
   *
623
   * @param int $staticCacheHitCounter
624
   */
625
  public function setStaticCacheHitCounter(int $staticCacheHitCounter)
626
  {
627
    $this->staticCacheHitCounter = $staticCacheHitCounter;
628
  }
629
630
  /**
631
   * Set cache-item by key => value + date.
632
   *
633
   * @param string    $key
634
   * @param mixed     $value
635
   * @param \DateTime $date <p>If the date is in the past, we will remove the existing cache-item.</p>
636
   *
637
   * @return bool
638
   *
639
   * @throws InvalidArgumentException <p>If the $date is in the past.</p>
640
   */
641 13
  public function setItemToDate(string $key, $value, \DateTime $date): bool
642
  {
643 13
    $ttl = $date->getTimestamp() - \time();
644
645 13
    if ($ttl <= 0) {
646 1
      throw new InvalidArgumentException('Date in the past.');
647
    }
648
649 12
    return $this->setItem($key, $value, $ttl);
650
  }
651
652
  /**
653
   * Set cache-item by key => value + ttl.
654
   *
655
   * @param string                 $key
656
   * @param mixed                  $value
657
   * @param null|int|\DateInterval $ttl
658
   *
659
   * @return bool
660
   *
661
   * @throws InvalidArgumentException
662
   */
663 32
  public function setItem(string $key, $value, $ttl = 0): bool
664
  {
665
    if (
666 32
        !$this->adapter instanceof iAdapter
667
        ||
668 32
        !$this->serializer instanceof iSerializer
669
    ) {
670
      return false;
671
    }
672
673 32
    $storeKey = $this->calculateStoreKey($key);
674 32
    $serialized = $this->serializer->serialize($value);
675
676
    // update static-cache, if it's exists
677 32
    if (\array_key_exists($storeKey, self::$STATIC_CACHE) === true) {
678 5
      self::$STATIC_CACHE[$storeKey] = $value;
679
    }
680
681 32
    if ($ttl) {
682
683 16
      if ($ttl instanceof \DateInterval) {
684
        // Converting to a TTL in seconds
685 1
        $dateTimeNow = new \DateTime('now');
686 1
        $ttl = $dateTimeNow->add($ttl)->getTimestamp() - \time();
687
      }
688
689
      // always cache the TTL time, maybe we need this later ...
690 16
      self::$STATIC_CACHE_EXPIRE[$storeKey] = ($ttl ? (int)$ttl + \time() : 0);
691
692 16
      return $this->adapter->setExpired($storeKey, $serialized, $ttl);
693
    }
694
695 16
    return $this->adapter->set($storeKey, $serialized);
696
  }
697
698
  /**
699
   * Remove a cached-item.
700
   *
701
   * @param string $key
702
   *
703
   * @return bool
704
   */
705 5
  public function removeItem(string $key): bool
706
  {
707 5
    if (!$this->adapter instanceof iAdapter) {
708
      return false;
709
    }
710
711 5
    $storeKey = $this->calculateStoreKey($key);
712
713
    // remove static-cache
714
    if (
715 5
        !empty(self::$STATIC_CACHE)
716
        &&
717 5
        \array_key_exists($storeKey, self::$STATIC_CACHE) === true
718
    ) {
719
      unset(
720
          self::$STATIC_CACHE[$storeKey],
721
          self::$STATIC_CACHE_COUNTER[$storeKey],
722
          self::$STATIC_CACHE_EXPIRE[$storeKey]
723
      );
724
    }
725
726 5
    return $this->adapter->remove($storeKey);
727
  }
728
729
  /**
730
   * Remove all cached-items.
731
   *
732
   * @return bool
733
   */
734 3
  public function removeAll(): bool
735
  {
736 3
    if (!$this->adapter instanceof iAdapter) {
737
      return false;
738
    }
739
740
    // remove static-cache
741 3
    if (!empty(self::$STATIC_CACHE)) {
742 3
      self::$STATIC_CACHE = [];
743 3
      self::$STATIC_CACHE_COUNTER = [];
744 3
      self::$STATIC_CACHE_EXPIRE = [];
745
    }
746
747 3
    return $this->adapter->removeAll();
748
  }
749
750
  /**
751
   * Check if cached-item exists.
752
   *
753
   * @param string $key
754
   *
755
   * @return bool
756
   */
757 11
  public function existsItem(string $key): bool
758
  {
759 11
    if (!$this->adapter instanceof iAdapter) {
760
      return false;
761
    }
762
763 11
    $storeKey = $this->calculateStoreKey($key);
764
765
    // check static-cache
766 11
    if ($this->checkForStaticCache($storeKey) === true) {
767
      return true;
768
    }
769
770 11
    return $this->adapter->exists($storeKey);
771
  }
772
773
  /**
774
   * @param string $storeKey
775
   *
776
   * @return bool
777
   */
778 36
  protected function checkForStaticCache(string $storeKey): bool
779
  {
780 36
    return !empty(self::$STATIC_CACHE)
781
           &&
782 36
           \array_key_exists($storeKey, self::$STATIC_CACHE) === true
783
           &&
784 36
           \array_key_exists($storeKey, self::$STATIC_CACHE_EXPIRE) === true
785
           &&
786 36
           \time() <= self::$STATIC_CACHE_EXPIRE[$storeKey];
787
  }
788
789
  /**
790
   * Get the current adapter class-name.
791
   *
792
   * @return string
793
   */
794 3
  public function getUsedAdapterClassName(): string
795
  {
796 3
    if ($this->adapter) {
797
      /** @noinspection GetClassUsageInspection */
798 3
      return \get_class($this->adapter);
799
    }
800
801
    return '';
802
  }
803
804
  /**
805
   * Get the current serializer class-name.
806
   *
807
   * @return string
808
   */
809 3
  public function getUsedSerializerClassName(): string
810
  {
811 3
    if ($this->serializer) {
812
      /** @noinspection GetClassUsageInspection */
813 3
      return \get_class($this->serializer);
814
    }
815
816
    return '';
817
  }
818
}
819