MongoId::createId()   A
last analyzed

Complexity

Conditions 2
Paths 1

Size

Total Lines 12
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 12
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 8
nc 1
nop 1
1
<?php
2
3
namespace Saxulum\MongoId;
4
5
class MongoId implements \Serializable
6
{
7
    /**
8
     * @var string
9
     */
10
    private $id;
11
12
    /**
13
     * @param MongoId|string|null $id
14
     *
15
     * @throws \InvalidArgumentException
16
     */
17
    public function __construct($id = null)
18
    {
19
        if ($id instanceof self) {
20
            $this->id = $id->id;
21
22
            return;
23
        }
24
25
        if (null !== $id) {
26
            if (!self::isValid($id)) {
27
                throw new \InvalidArgumentException(sprintf('Invalid id: %s', $id));
28
            }
29
            $this->id = $id;
30
31
            return;
32
        }
33
34
        $this->id = $this->createId();
35
    }
36
37
    /**
38
     * @param \DateTime $dateTime
39
     *
40
     * @return object
41
     */
42
    public static function createByDateTime(\DateTime $dateTime)
43
    {
44
        $object = new static;
45
        $object->id = $object->createId($dateTime->format('U'));
46
47
        return $object;
48
    }
49
50
    /**
51
     * @param int|null $time
52
     *
53
     * @return string
54
     */
55
    private function createId($time = null)
56
    {
57
        $pid = getmypid();
58
        $inc = $this->readInc($pid);
59
60
        $id = $this->intToMaxLengthHex(null !== $time ? (int) $time : time(), 8);
61
        $id .= $this->intToMaxLengthHex(crc32(self::getHostname()), 6);
62
        $id .= $this->intToMaxLengthHex($pid, 4);
63
        $id .= $this->intToMaxLengthHex($inc, 6);
64
65
        return $id;
66
    }
67
68
    /**
69
     * @param int $pid
70
     *
71
     * @return int
72
     */
73
    private function readInc($pid)
74
    {
75
        $res = shm_attach($pid);
76
        if (!shm_has_var($res, 0)) {
77
            shm_put_var($res, 0, 0);
78
        }
79
80
        $inc = shm_get_var($res, 0);
81
        if ($inc === 16777215) {
82
            $inc = 0;
83
        }
84
85
        ++$inc;
86
87
        shm_put_var($res, 0, $inc);
88
89
        return $inc;
90
    }
91
92
    /**
93
     * @param int $value
94
     * @param int $length
95
     *
96
     * @return string
97
     */
98
    private function intToMaxLengthHex($value, $length)
99
    {
100
        return str_pad(substr(dechex($value), 0, $length), $length, '0', STR_PAD_LEFT);
101
    }
102
103
    /**
104
     * @return string
105
     */
106
    public static function getHostname()
107
    {
108
        return gethostname();
109
    }
110
111
    /**
112
     * @return int
113
     */
114
    public function getInc()
115
    {
116
        return hexdec(substr($this->id, 18, 6));
117
    }
118
119
    /**
120
     * @return int
121
     */
122
    public function getPID()
123
    {
124
        $pid = hexdec(substr($this->id, 14, 4));
125
126
        return $pid;
127
    }
128
129
    /**
130
     * @return int
131
     */
132
    public function getTimestamp()
133
    {
134
        return hexdec(substr($this->id, 0, 8));
135
    }
136
137
    /**
138
     * @param string $value
139
     *
140
     * @return bool
141
     */
142
    public static function isValid($value)
143
    {
144
        if (strlen($value) !== 24) {
145
            return false;
146
        }
147
148
        if (strspn($value, '0123456789abcdefABCDEF') !== 24) {
149
            return false;
150
        }
151
152
        return true;
153
    }
154
155
    /**
156
     * @param array $props
157
     *
158
     * @return static
159
     *
160
     * @throws \InvalidArgumentException
161
     */
162
    public static function __set_state(array $props)
163
    {
164
        if (!isset($props['id'])) {
165
            throw new \InvalidArgumentException('There is no id key within props array!');
166
        }
167
168
        return new static($props['id']);
169
    }
170
171
    /**
172
     * @return string
173
     */
174
    public function __toString()
175
    {
176
        return $this->id;
177
    }
178
179
    /**
180
     * @return string
181
     */
182
    public function serialize()
183
    {
184
        return $this->id;
185
    }
186
187
    /**
188
     * @param string $serialized
189
     *
190
     * @throws \InvalidArgumentException
191
     */
192
    public function unserialize($serialized)
193
    {
194
        if (!self::isValid($serialized)) {
195
            throw new \InvalidArgumentException(sprintf('Invalid id: %s', $serialized));
196
        }
197
        $this->id = $serialized;
198
    }
199
}
200