UuidIdentity::generateBytes()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 9
rs 9.6667
cc 2
eloc 5
nc 2
nop 1
1
<?php
2
3
namespace Domain\Identity;
4
5
/**
6
 * @author Sebastiaan Hilbers <[email protected]>
7
 */
8
abstract class UuidIdentity implements Identity, Generator
9
{
10
    /**
11
     * @var string
12
     */
13
    private $uuid;
14
15
    private function __construct($uuid)
0 ignored issues
show
introduced by
Something seems to be off here. Are you sure you want to declare the constructor as private, and the class as abstract?
Loading history...
16
    {
17
        $this->uuid = $uuid;
18
    }
19
20
    /**
21
     * Generates a UUID v4 Identity
22
     * @return static
23
     */
24
    public static function generate()
25
    {
26
        return new static(self::uuid4());
27
    }
28
29
    /**
30
     * Creates an identifier object from a string representation
31
     * @param $string
32
     * @return static
33
     */
34
    public static function fromString($string)
35
    {
36
        self::guardUuid($string);
37
        return new static($string);
38
    }
39
40
    /**
41
     * Returns a string that can be parsed by fromString()
42
     * @return string
43
     */
44
    public function __toString()
45
    {
46
        return (string) $this->uuid;
47
    }
48
49
    /**
50
     * Compares the object to another IdentifiesAggregate object. Returns true if both have the same type and value.
51
     * @param Identity $other
52
     * @return boolean
53
     */
54
    public function equals(Identity $other)
55
    {
56
        return $other instanceof static && $this->uuid == $other->uuid;
57
    }
58
59
    /**
60
     * Returns a version 4 UUID
61
     * @return string
62
     */
63
    private static function uuid4()
64
    {
65
        $bytes = function_exists('openssl_random_pseudo_bytes')
66
            ? openssl_random_pseudo_bytes(16)
67
            : self::generateBytes(16)
68
        ;
69
70
        $hash = bin2hex($bytes);
71
72
        // Set the version number
73
        $timeHi = hexdec(substr($hash, 12, 4)) & 0x0fff;
74
        $timeHi &= ~(0xf000);
75
        $timeHi |= 4 << 12;
76
77
        // Set the variant to RFC 4122
78
        $clockSeqHi = hexdec(substr($hash, 16, 2)) & 0x3f;
79
        $clockSeqHi &= ~(0xc0);
80
        $clockSeqHi |= 0x80;
81
82
        $fields = [
83
            'time_low' => substr($hash, 0, 8),
84
            'time_mid' => substr($hash, 8, 4),
85
            'time_hi_and_version' => sprintf('%04x', $timeHi),
86
            'clock_seq_hi_and_reserved' => sprintf('%02x', $clockSeqHi),
87
            'clock_seq_low' => substr($hash, 18, 2),
88
            'node' => substr($hash, 20, 12),
89
        ];
90
91
        return vsprintf(
92
            '%08s-%04s-%04s-%02s%02s-%012s',
93
            $fields
94
        );
95
    }
96
97
    private static function generateBytes($length)
98
    {
99
        $bytes = '';
100
        foreach (range(1, $length) as $i) {
101
            $bytes = chr(mt_rand(0, 256)) . $bytes;
102
        }
103
104
        return $bytes;
105
    }
106
107
    private static function guardUuid($string)
108
    {
109
        $pattern = '/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i';
110
        if (!preg_match($pattern, $string)) {
111
            throw new \InvalidArgumentException("UUID of the form nnnnnnnn-nnnn-nnnn-nnnn-nnnnnnnnnnnn expected");
112
        }
113
    }
114
}
115