Completed
Push — master ( 09b86b...ba0798 )
by Andreas
20:05 queued 12s
created

UuidGenerator   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 130
Duplicated Lines 6.15 %

Coupling/Cohesion

Components 1
Dependencies 1

Test Coverage

Coverage 92.86%

Importance

Changes 0
Metric Value
wmc 11
lcom 1
cbo 1
dl 8
loc 130
ccs 39
cts 42
cp 0.9286
rs 10
c 0
b 0
f 0

7 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 8 8 2
A setSalt() 0 4 1
A getSalt() 0 4 1
A isValid() 0 5 1
A generate() 0 5 2
A generateV4() 0 22 1
A generateV5() 0 37 3

How to fix   Duplicated Code   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

1
<?php
2
3
declare(strict_types=1);
4
5
namespace Doctrine\ODM\MongoDB\Id;
6
7
use Doctrine\ODM\MongoDB\DocumentManager;
8
use Exception;
9
use const E_USER_DEPRECATED;
10
use function chr;
11
use function hexdec;
12
use function mt_rand;
13
use function php_uname;
14
use function preg_match;
15
use function sha1;
16
use function sprintf;
17
use function str_replace;
18
use function strlen;
19
use function substr;
20
use function trigger_error;
21
22
/**
23
 * Generates UUIDs.
24
 *
25
 * @final
26
 */
27
class UuidGenerator extends AbstractIdGenerator
28
{
29
    /**
30
     * A unique environment value to salt each UUID with.
31
     *
32
     * @var string
33
     */
34
    protected $salt = null;
35
36 6 View Code Duplication
    public function __construct()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
37
    {
38 6
        if (self::class === static::class) {
39 6
            return;
40
        }
41
42
        @trigger_error(sprintf('The class "%s" extends "%s" which will be final in MongoDB ODM 2.0.', static::class, self::class), E_USER_DEPRECATED);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
43
    }
44
45
    /**
46
     * Used to set the salt that will be applied to each id
47
     */
48 2
    public function setSalt(string $salt) : void
49
    {
50 2
        $this->salt = $salt;
51 2
    }
52
53
    /**
54
     * Returns the current salt value
55
     *
56
     * @return string $salt The current salt
57
     */
58 1
    public function getSalt() : string
59
    {
60 1
        return $this->salt;
61
    }
62
63
    /**
64
     * Checks that a given string is a valid uuid.
65
     */
66 2
    public function isValid(string $uuid) : bool
67
    {
68 2
        return preg_match('/^\{?[0-9a-f]{8}\-?[0-9a-f]{4}\-?[0-9a-f]{4}\-?[0-9a-f]{4}\-?[0-9a-f]{12}\}?$/i', $uuid)
69 2
            === 1;
70
    }
71
72
    /**
73
     * Generates a new UUID
74
     *
75
     * @param DocumentManager $dm       Not used.
76
     * @param object          $document Not used.
77
     *
78
     * @return string UUID
79
     *
80
     * @throws Exception
81
     */
82 2
    public function generate(DocumentManager $dm, object $document)
83
    {
84 2
        $uuid = $this->generateV4();
85 2
        return $this->generateV5($uuid, $this->salt ?: php_uname('n'));
86
    }
87
88
    /**
89
     * Generates a v4 UUID
90
     */
91 4
    public function generateV4() : string
92
    {
93 4
        return sprintf(
94 4
            '%04x%04x%04x%04x%04x%04x%04x%04x',
95
            // 32 bits for "time_low"
96 4
            mt_rand(0, 0xffff),
97 4
            mt_rand(0, 0xffff),
98
            // 16 bits for "time_mid"
99 4
            mt_rand(0, 0xffff),
100
            // 16 bits for "time_hi_and_version",
101
            // four most significant bits holds version number 4
102 4
            mt_rand(0, 0x0fff) | 0x4000,
103
            // 16 bits, 8 bits for "clk_seq_hi_res",
104
            // 8 bits for "clk_seq_low",
105
            // two most significant bits holds zero and one for variant DCE1.1
106 4
            mt_rand(0, 0x3fff) | 0x8000,
107
            // 48 bits for "node"
108 4
            mt_rand(0, 0xffff),
109 4
            mt_rand(0, 0xffff),
110 4
            mt_rand(0, 0xffff)
111
        );
112
    }
113
114
    /**
115
     * Generates a v5 UUID
116
     *
117
     * @throws Exception When the provided namespace is invalid.
118
     */
119 2
    public function generateV5(string $namespace, string $salt) : string
120
    {
121 2
        if (! $this->isValid($namespace)) {
122
            throw new Exception('Provided $namespace is invalid: ' . $namespace);
123
        }
124
125
        // Get hexadecimal components of namespace
126 2
        $nhex = str_replace(['-', '{', '}'], '', $namespace);
127
128
        // Binary Value
129 2
        $nstr = '';
130
131
        // Convert Namespace UUID to bits
132 2
        for ($i = 0; $i < strlen($nhex); $i += 2) {
133 2
            $nstr .= chr((int) hexdec($nhex[$i] . $nhex[$i + 1]));
134
        }
135
136
        // Calculate hash value
137 2
        $hash = sha1($nstr . $salt);
138
139 2
        return sprintf(
140 2
            '%08s%04s%04x%04x%12s',
141
            // 32 bits for "time_low"
142 2
            substr($hash, 0, 8),
143
            // 16 bits for "time_mid"
144 2
            substr($hash, 8, 4),
145
            // 16 bits for "time_hi_and_version",
146
            // four most significant bits holds version number 3
147 2
            (hexdec(substr($hash, 12, 4)) & 0x0fff) | 0x3000,
148
            // 16 bits, 8 bits for "clk_seq_hi_res",
149
            // 8 bits for "clk_seq_low",
150
            // two most significant bits holds zero and one for variant DCE1.1
151 2
            (hexdec(substr($hash, 16, 4)) & 0x3fff) | 0x8000,
152
            // 48 bits for "node"
153 2
            substr($hash, 20, 12)
154
        );
155
    }
156
}
157