UuidIdentity   A
last analyzed

Complexity

Total Complexity 12

Size/Duplication

Total Lines 107
Duplicated Lines 0 %

Coupling/Cohesion

Components 2
Dependencies 0

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 107
wmc 12
lcom 2
cbo 0
rs 10

8 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A generate() 0 4 1
A fromString() 0 5 1
A __toString() 0 4 1
A equals() 0 4 2
B uuid4() 0 33 2
A generateBytes() 0 9 2
A guardUuid() 0 7 2
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