Subversion-Projekte lars-tiefland.laravel_shop

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
/**
4
 * This file is part of the ramsey/uuid library
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 *
9
 * @copyright Copyright (c) Ben Ramsey <ben@benramsey.com>
10
 * @license http://opensource.org/licenses/MIT MIT
11
 */
12
 
13
declare(strict_types=1);
14
 
15
namespace Ramsey\Uuid\Lazy;
16
 
17
use DateTimeInterface;
18
use Ramsey\Uuid\Converter\NumberConverterInterface;
19
use Ramsey\Uuid\Exception\UnsupportedOperationException;
20
use Ramsey\Uuid\Fields\FieldsInterface;
21
use Ramsey\Uuid\Rfc4122\UuidV1;
22
use Ramsey\Uuid\Rfc4122\UuidV6;
23
use Ramsey\Uuid\Type\Hexadecimal;
24
use Ramsey\Uuid\Type\Integer as IntegerObject;
25
use Ramsey\Uuid\UuidFactory;
26
use Ramsey\Uuid\UuidInterface;
27
use ValueError;
28
 
29
use function assert;
30
use function bin2hex;
31
use function hex2bin;
32
use function sprintf;
33
use function str_replace;
34
use function substr;
35
 
36
/**
37
 * Lazy version of a UUID: its format has not been determined yet, so it is mostly only usable for string/bytes
38
 * conversion. This object optimizes instantiation, serialization and string conversion time, at the cost of
39
 * increased overhead for more advanced UUID operations.
40
 *
41
 * @internal this type is used internally for performance reasons, and is not supposed to be directly referenced
42
 *           in consumer libraries.
43
 *
44
 * @psalm-immutable
45
 *
46
 * Note: the {@see FieldsInterface} does not declare methods that deprecated API
47
 *        relies upon: the API has been ported from the {@see \Ramsey\Uuid\Uuid} definition,
48
 *        and is deprecated anyway.
49
 * Note: the deprecated API from {@see \Ramsey\Uuid\Uuid} is in use here (on purpose): it will be removed
50
 *       once the deprecated API is gone from this class too.
51
 *
52
 * @psalm-suppress UndefinedInterfaceMethod
53
 * @psalm-suppress DeprecatedMethod
54
 */
55
final class LazyUuidFromString implements UuidInterface
56
{
57
    public const VALID_REGEX = '/\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/ms';
58
 
59
    private ?UuidInterface $unwrapped = null;
60
 
61
    /**
62
     * @psalm-param non-empty-string $uuid
63
     */
64
    public function __construct(private string $uuid)
65
    {
66
    }
67
 
68
    /** @psalm-pure */
69
    public static function fromBytes(string $bytes): self
70
    {
71
        $base16Uuid = bin2hex($bytes);
72
 
73
        return new self(
74
            substr($base16Uuid, 0, 8)
75
            . '-'
76
            . substr($base16Uuid, 8, 4)
77
            . '-'
78
            . substr($base16Uuid, 12, 4)
79
            . '-'
80
            . substr($base16Uuid, 16, 4)
81
            . '-'
82
            . substr($base16Uuid, 20, 12)
83
        );
84
    }
85
 
86
    public function serialize(): string
87
    {
88
        return $this->uuid;
89
    }
90
 
91
    /**
92
     * @return array{string: string}
93
     *
94
     * @psalm-return array{string: non-empty-string}
95
     */
96
    public function __serialize(): array
97
    {
98
        return ['string' => $this->uuid];
99
    }
100
 
101
    /**
102
     * {@inheritDoc}
103
     *
104
     * @param string $data
105
     *
106
     * @psalm-param non-empty-string $data
107
     */
108
    public function unserialize(string $data): void
109
    {
110
        $this->uuid = $data;
111
    }
112
 
113
    /**
114
     * @param array{string?: string} $data
115
     *
116
     * @psalm-param array{string?: non-empty-string} $data
117
     * @psalm-suppress UnusedMethodCall
118
     */
119
    public function __unserialize(array $data): void
120
    {
121
        // @codeCoverageIgnoreStart
122
        if (!isset($data['string'])) {
123
            throw new ValueError(sprintf('%s(): Argument #1 ($data) is invalid', __METHOD__));
124
        }
125
        // @codeCoverageIgnoreEnd
126
 
127
        $this->unserialize($data['string']);
128
    }
129
 
130
    /** @psalm-suppress DeprecatedMethod */
131
    public function getNumberConverter(): NumberConverterInterface
132
    {
133
        return ($this->unwrapped ?? $this->unwrap())
134
            ->getNumberConverter();
135
    }
136
 
137
    /**
138
     * {@inheritDoc}
139
     *
140
     * @psalm-suppress DeprecatedMethod
141
     */
142
    public function getFieldsHex(): array
143
    {
144
        return ($this->unwrapped ?? $this->unwrap())
145
            ->getFieldsHex();
146
    }
147
 
148
    /** @psalm-suppress DeprecatedMethod */
149
    public function getClockSeqHiAndReservedHex(): string
150
    {
151
        return ($this->unwrapped ?? $this->unwrap())
152
            ->getClockSeqHiAndReservedHex();
153
    }
154
 
155
    /** @psalm-suppress DeprecatedMethod */
156
    public function getClockSeqLowHex(): string
157
    {
158
        return ($this->unwrapped ?? $this->unwrap())
159
            ->getClockSeqLowHex();
160
    }
161
 
162
    /** @psalm-suppress DeprecatedMethod */
163
    public function getClockSequenceHex(): string
164
    {
165
        return ($this->unwrapped ?? $this->unwrap())
166
            ->getClockSequenceHex();
167
    }
168
 
169
    /** @psalm-suppress DeprecatedMethod */
170
    public function getDateTime(): DateTimeInterface
171
    {
172
        return ($this->unwrapped ?? $this->unwrap())
173
            ->getDateTime();
174
    }
175
 
176
    /** @psalm-suppress DeprecatedMethod */
177
    public function getLeastSignificantBitsHex(): string
178
    {
179
        return ($this->unwrapped ?? $this->unwrap())
180
            ->getLeastSignificantBitsHex();
181
    }
182
 
183
    /** @psalm-suppress DeprecatedMethod */
184
    public function getMostSignificantBitsHex(): string
185
    {
186
        return ($this->unwrapped ?? $this->unwrap())
187
            ->getMostSignificantBitsHex();
188
    }
189
 
190
    /** @psalm-suppress DeprecatedMethod */
191
    public function getNodeHex(): string
192
    {
193
        return ($this->unwrapped ?? $this->unwrap())
194
            ->getNodeHex();
195
    }
196
 
197
    /** @psalm-suppress DeprecatedMethod */
198
    public function getTimeHiAndVersionHex(): string
199
    {
200
        return ($this->unwrapped ?? $this->unwrap())
201
            ->getTimeHiAndVersionHex();
202
    }
203
 
204
    /** @psalm-suppress DeprecatedMethod */
205
    public function getTimeLowHex(): string
206
    {
207
        return ($this->unwrapped ?? $this->unwrap())
208
            ->getTimeLowHex();
209
    }
210
 
211
    /** @psalm-suppress DeprecatedMethod */
212
    public function getTimeMidHex(): string
213
    {
214
        return ($this->unwrapped ?? $this->unwrap())
215
            ->getTimeMidHex();
216
    }
217
 
218
    /** @psalm-suppress DeprecatedMethod */
219
    public function getTimestampHex(): string
220
    {
221
        return ($this->unwrapped ?? $this->unwrap())
222
            ->getTimestampHex();
223
    }
224
 
225
    /** @psalm-suppress DeprecatedMethod */
226
    public function getUrn(): string
227
    {
228
        return ($this->unwrapped ?? $this->unwrap())
229
            ->getUrn();
230
    }
231
 
232
    /** @psalm-suppress DeprecatedMethod */
233
    public function getVariant(): ?int
234
    {
235
        return ($this->unwrapped ?? $this->unwrap())
236
            ->getVariant();
237
    }
238
 
239
    /** @psalm-suppress DeprecatedMethod */
240
    public function getVersion(): ?int
241
    {
242
        return ($this->unwrapped ?? $this->unwrap())
243
            ->getVersion();
244
    }
245
 
246
    public function compareTo(UuidInterface $other): int
247
    {
248
        return ($this->unwrapped ?? $this->unwrap())
249
            ->compareTo($other);
250
    }
251
 
252
    public function equals(?object $other): bool
253
    {
254
        if (! $other instanceof UuidInterface) {
255
            return false;
256
        }
257
 
258
        return $this->uuid === $other->toString();
259
    }
260
 
261
    /**
262
     * {@inheritDoc}
263
     *
264
     * @psalm-suppress MoreSpecificReturnType
265
     * @psalm-suppress LessSpecificReturnStatement we know that {@see self::$uuid} is a non-empty string, so
266
     *                                             we know that {@see hex2bin} will retrieve a non-empty string too.
267
     */
268
    public function getBytes(): string
269
    {
270
        /** @phpstan-ignore-next-line PHPStan complains that this is not a non-empty-string. */
271
        return (string) hex2bin(str_replace('-', '', $this->uuid));
272
    }
273
 
274
    public function getFields(): FieldsInterface
275
    {
276
        return ($this->unwrapped ?? $this->unwrap())
277
            ->getFields();
278
    }
279
 
280
    public function getHex(): Hexadecimal
281
    {
282
        return ($this->unwrapped ?? $this->unwrap())
283
            ->getHex();
284
    }
285
 
286
    public function getInteger(): IntegerObject
287
    {
288
        return ($this->unwrapped ?? $this->unwrap())
289
            ->getInteger();
290
    }
291
 
292
    public function toString(): string
293
    {
294
        return $this->uuid;
295
    }
296
 
297
    public function __toString(): string
298
    {
299
        return $this->uuid;
300
    }
301
 
302
    public function jsonSerialize(): string
303
    {
304
        return $this->uuid;
305
    }
306
 
307
    /**
308
     * @deprecated Use {@see UuidInterface::getFields()} to get a
309
     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
310
     *     instance, you may call {@see Rfc4122FieldsInterface::getClockSeqHiAndReserved()}
311
     *     and use the arbitrary-precision math library of your choice to
312
     *     convert it to a string integer.
313
     *
314
     * @psalm-suppress UndefinedInterfaceMethod
315
     * @psalm-suppress DeprecatedMethod
316
     * @psalm-suppress MixedArgument
317
     * @psalm-suppress MixedMethodCall
318
     */
319
    public function getClockSeqHiAndReserved(): string
320
    {
321
        $instance = ($this->unwrapped ?? $this->unwrap());
322
 
323
        return $instance->getNumberConverter()
324
            ->fromHex(
325
                $instance->getFields()
326
                    ->getClockSeqHiAndReserved()
327
                    ->toString()
328
            );
329
    }
330
 
331
    /**
332
     * @deprecated Use {@see UuidInterface::getFields()} to get a
333
     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
334
     *     instance, you may call {@see Rfc4122FieldsInterface::getClockSeqLow()}
335
     *     and use the arbitrary-precision math library of your choice to
336
     *     convert it to a string integer.
337
     *
338
     * @psalm-suppress UndefinedInterfaceMethod
339
     * @psalm-suppress DeprecatedMethod
340
     * @psalm-suppress MixedArgument
341
     * @psalm-suppress MixedMethodCall
342
     */
343
    public function getClockSeqLow(): string
344
    {
345
        $instance = ($this->unwrapped ?? $this->unwrap());
346
 
347
        return $instance->getNumberConverter()
348
            ->fromHex(
349
                $instance->getFields()
350
                    ->getClockSeqLow()
351
                    ->toString()
352
            );
353
    }
354
 
355
    /**
356
     * @deprecated Use {@see UuidInterface::getFields()} to get a
357
     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
358
     *     instance, you may call {@see Rfc4122FieldsInterface::getClockSeq()}
359
     *     and use the arbitrary-precision math library of your choice to
360
     *     convert it to a string integer.
361
     *
362
     * @psalm-suppress UndefinedInterfaceMethod
363
     * @psalm-suppress DeprecatedMethod
364
     * @psalm-suppress MixedArgument
365
     * @psalm-suppress MixedMethodCall
366
     */
367
    public function getClockSequence(): string
368
    {
369
        $instance = ($this->unwrapped ?? $this->unwrap());
370
 
371
        return $instance->getNumberConverter()
372
            ->fromHex(
373
                $instance->getFields()
374
                    ->getClockSeq()
375
                    ->toString()
376
            );
377
    }
378
 
379
    /**
380
     * @deprecated This method will be removed in 5.0.0. There is no direct
381
     *     alternative, but the same information may be obtained by splitting
382
     *     in half the value returned by {@see UuidInterface::getHex()}.
383
     *
384
     * @psalm-suppress UndefinedInterfaceMethod
385
     * @psalm-suppress DeprecatedMethod
386
     * @psalm-suppress MixedArgument
387
     * @psalm-suppress MixedMethodCall
388
     */
389
    public function getLeastSignificantBits(): string
390
    {
391
        $instance = ($this->unwrapped ?? $this->unwrap());
392
 
393
        return $instance->getNumberConverter()
394
            ->fromHex(substr($instance->getHex()->toString(), 16));
395
    }
396
 
397
    /**
398
     * @deprecated This method will be removed in 5.0.0. There is no direct
399
     *     alternative, but the same information may be obtained by splitting
400
     *     in half the value returned by {@see UuidInterface::getHex()}.
401
     *
402
     * @psalm-suppress UndefinedInterfaceMethod
403
     * @psalm-suppress DeprecatedMethod
404
     * @psalm-suppress MixedArgument
405
     * @psalm-suppress MixedMethodCall
406
     */
407
    public function getMostSignificantBits(): string
408
    {
409
        $instance = ($this->unwrapped ?? $this->unwrap());
410
 
411
        return $instance->getNumberConverter()
412
            ->fromHex(substr($instance->getHex()->toString(), 0, 16));
413
    }
414
 
415
    /**
416
     * @deprecated Use {@see UuidInterface::getFields()} to get a
417
     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
418
     *     instance, you may call {@see Rfc4122FieldsInterface::getNode()}
419
     *     and use the arbitrary-precision math library of your choice to
420
     *     convert it to a string integer.
421
     *
422
     * @psalm-suppress UndefinedInterfaceMethod
423
     * @psalm-suppress DeprecatedMethod
424
     * @psalm-suppress MixedArgument
425
     * @psalm-suppress MixedMethodCall
426
     */
427
    public function getNode(): string
428
    {
429
        $instance = ($this->unwrapped ?? $this->unwrap());
430
 
431
        return $instance->getNumberConverter()
432
            ->fromHex(
433
                $instance->getFields()
434
                    ->getNode()
435
                    ->toString()
436
            );
437
    }
438
 
439
    /**
440
     * @deprecated Use {@see UuidInterface::getFields()} to get a
441
     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
442
     *     instance, you may call {@see Rfc4122FieldsInterface::getTimeHiAndVersion()}
443
     *     and use the arbitrary-precision math library of your choice to
444
     *     convert it to a string integer.
445
     *
446
     * @psalm-suppress UndefinedInterfaceMethod
447
     * @psalm-suppress DeprecatedMethod
448
     * @psalm-suppress MixedArgument
449
     * @psalm-suppress MixedMethodCall
450
     */
451
    public function getTimeHiAndVersion(): string
452
    {
453
        $instance = ($this->unwrapped ?? $this->unwrap());
454
 
455
        return $instance->getNumberConverter()
456
            ->fromHex(
457
                $instance->getFields()
458
                    ->getTimeHiAndVersion()
459
                    ->toString()
460
            );
461
    }
462
 
463
    /**
464
     * @deprecated Use {@see UuidInterface::getFields()} to get a
465
     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
466
     *     instance, you may call {@see Rfc4122FieldsInterface::getTimeLow()}
467
     *     and use the arbitrary-precision math library of your choice to
468
     *     convert it to a string integer.
469
     *
470
     * @psalm-suppress UndefinedInterfaceMethod
471
     * @psalm-suppress DeprecatedMethod
472
     * @psalm-suppress MixedArgument
473
     * @psalm-suppress MixedMethodCall
474
     */
475
    public function getTimeLow(): string
476
    {
477
        $instance = ($this->unwrapped ?? $this->unwrap());
478
 
479
        return $instance->getNumberConverter()
480
            ->fromHex(
481
                $instance->getFields()
482
                    ->getTimeLow()
483
                    ->toString()
484
            );
485
    }
486
 
487
    /**
488
     * @deprecated Use {@see UuidInterface::getFields()} to get a
489
     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
490
     *     instance, you may call {@see Rfc4122FieldsInterface::getTimeMid()}
491
     *     and use the arbitrary-precision math library of your choice to
492
     *     convert it to a string integer.
493
     *
494
     * @psalm-suppress UndefinedInterfaceMethod
495
     * @psalm-suppress DeprecatedMethod
496
     * @psalm-suppress MixedArgument
497
     * @psalm-suppress MixedMethodCall
498
     */
499
    public function getTimeMid(): string
500
    {
501
        $instance = ($this->unwrapped ?? $this->unwrap());
502
 
503
        return $instance->getNumberConverter()
504
            ->fromHex(
505
                $instance->getFields()
506
                    ->getTimeMid()
507
                    ->toString()
508
            );
509
    }
510
 
511
    /**
512
     * @deprecated Use {@see UuidInterface::getFields()} to get a
513
     *     {@see FieldsInterface} instance. If it is a {@see Rfc4122FieldsInterface}
514
     *     instance, you may call {@see Rfc4122FieldsInterface::getTimestamp()}
515
     *     and use the arbitrary-precision math library of your choice to
516
     *     convert it to a string integer.
517
     *
518
     * @psalm-suppress UndefinedInterfaceMethod
519
     * @psalm-suppress DeprecatedMethod
520
     * @psalm-suppress MixedArgument
521
     * @psalm-suppress MixedMethodCall
522
     */
523
    public function getTimestamp(): string
524
    {
525
        $instance = ($this->unwrapped ?? $this->unwrap());
526
        $fields = $instance->getFields();
527
 
528
        if ($fields->getVersion() !== 1) {
529
            throw new UnsupportedOperationException('Not a time-based UUID');
530
        }
531
 
532
        return $instance->getNumberConverter()
533
            ->fromHex($fields->getTimestamp()->toString());
534
    }
535
 
536
    public function toUuidV1(): UuidV1
537
    {
538
        $instance = ($this->unwrapped ?? $this->unwrap());
539
 
540
        if ($instance instanceof UuidV1) {
541
            return $instance;
542
        }
543
 
544
        assert($instance instanceof UuidV6);
545
 
546
        return $instance->toUuidV1();
547
    }
548
 
549
    public function toUuidV6(): UuidV6
550
    {
551
        $instance = ($this->unwrapped ?? $this->unwrap());
552
 
553
        assert($instance instanceof UuidV6);
554
 
555
        return $instance;
556
    }
557
 
558
    /**
559
     * @psalm-suppress ImpureMethodCall the retrieval of the factory is a clear violation of purity here: this is a
560
     *                                  known pitfall of the design of this library, where a value object contains
561
     *                                  a mutable reference to a factory. We use a fixed factory here, so the violation
562
     *                                  will not have real-world effects, as this object is only instantiated with the
563
     *                                  default factory settings/features.
564
     * @psalm-suppress InaccessibleProperty property {@see $unwrapped} is used as a cache: we don't expose it to the
565
     *                                      outside world, so we should be fine here.
566
     */
567
    private function unwrap(): UuidInterface
568
    {
569
        return $this->unwrapped = (new UuidFactory())
570
            ->fromString($this->uuid);
571
    }
572
}