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 13declare(strict_types=1); 14 15namespace Ramsey\Uuid; 16 17use Ramsey\Uuid\Builder\BuilderCollection; 18use Ramsey\Uuid\Builder\FallbackBuilder; 19use Ramsey\Uuid\Builder\UuidBuilderInterface; 20use Ramsey\Uuid\Codec\CodecInterface; 21use Ramsey\Uuid\Codec\GuidStringCodec; 22use Ramsey\Uuid\Codec\StringCodec; 23use Ramsey\Uuid\Converter\Number\GenericNumberConverter; 24use Ramsey\Uuid\Converter\NumberConverterInterface; 25use Ramsey\Uuid\Converter\Time\GenericTimeConverter; 26use Ramsey\Uuid\Converter\Time\PhpTimeConverter; 27use Ramsey\Uuid\Converter\TimeConverterInterface; 28use Ramsey\Uuid\Generator\DceSecurityGenerator; 29use Ramsey\Uuid\Generator\DceSecurityGeneratorInterface; 30use Ramsey\Uuid\Generator\NameGeneratorFactory; 31use Ramsey\Uuid\Generator\NameGeneratorInterface; 32use Ramsey\Uuid\Generator\PeclUuidNameGenerator; 33use Ramsey\Uuid\Generator\PeclUuidRandomGenerator; 34use Ramsey\Uuid\Generator\PeclUuidTimeGenerator; 35use Ramsey\Uuid\Generator\RandomGeneratorFactory; 36use Ramsey\Uuid\Generator\RandomGeneratorInterface; 37use Ramsey\Uuid\Generator\TimeGeneratorFactory; 38use Ramsey\Uuid\Generator\TimeGeneratorInterface; 39use Ramsey\Uuid\Guid\GuidBuilder; 40use Ramsey\Uuid\Math\BrickMathCalculator; 41use Ramsey\Uuid\Math\CalculatorInterface; 42use Ramsey\Uuid\Nonstandard\UuidBuilder as NonstandardUuidBuilder; 43use Ramsey\Uuid\Provider\Dce\SystemDceSecurityProvider; 44use Ramsey\Uuid\Provider\DceSecurityProviderInterface; 45use Ramsey\Uuid\Provider\Node\FallbackNodeProvider; 46use Ramsey\Uuid\Provider\Node\NodeProviderCollection; 47use Ramsey\Uuid\Provider\Node\RandomNodeProvider; 48use Ramsey\Uuid\Provider\Node\SystemNodeProvider; 49use Ramsey\Uuid\Provider\NodeProviderInterface; 50use Ramsey\Uuid\Provider\Time\SystemTimeProvider; 51use Ramsey\Uuid\Provider\TimeProviderInterface; 52use Ramsey\Uuid\Rfc4122\UuidBuilder as Rfc4122UuidBuilder; 53use Ramsey\Uuid\Validator\GenericValidator; 54use Ramsey\Uuid\Validator\ValidatorInterface; 55 56use const PHP_INT_SIZE; 57 58/** 59 * FeatureSet detects and exposes available features in the current environment 60 * 61 * A feature set is used by UuidFactory to determine the available features and 62 * capabilities of the environment. 63 */ 64class FeatureSet 65{ 66 /** 67 * @var bool 68 */ 69 private $disableBigNumber = false; 70 71 /** 72 * @var bool 73 */ 74 private $disable64Bit = false; 75 76 /** 77 * @var bool 78 */ 79 private $ignoreSystemNode = false; 80 81 /** 82 * @var bool 83 */ 84 private $enablePecl = false; 85 86 /** 87 * @var UuidBuilderInterface 88 */ 89 private $builder; 90 91 /** 92 * @var CodecInterface 93 */ 94 private $codec; 95 96 /** 97 * @var DceSecurityGeneratorInterface 98 */ 99 private $dceSecurityGenerator; 100 101 /** 102 * @var NameGeneratorInterface 103 */ 104 private $nameGenerator; 105 106 /** 107 * @var NodeProviderInterface 108 */ 109 private $nodeProvider; 110 111 /** 112 * @var NumberConverterInterface 113 */ 114 private $numberConverter; 115 116 /** 117 * @var TimeConverterInterface 118 */ 119 private $timeConverter; 120 121 /** 122 * @var RandomGeneratorInterface 123 */ 124 private $randomGenerator; 125 126 /** 127 * @var TimeGeneratorInterface 128 */ 129 private $timeGenerator; 130 131 /** 132 * @var TimeProviderInterface 133 */ 134 private $timeProvider; 135 136 /** 137 * @var ValidatorInterface 138 */ 139 private $validator; 140 141 /** 142 * @var CalculatorInterface 143 */ 144 private $calculator; 145 146 /** 147 * @param bool $useGuids True build UUIDs using the GuidStringCodec 148 * @param bool $force32Bit True to force the use of 32-bit functionality 149 * (primarily for testing purposes) 150 * @param bool $forceNoBigNumber True to disable the use of moontoast/math 151 * (primarily for testing purposes) 152 * @param bool $ignoreSystemNode True to disable attempts to check for the 153 * system node ID (primarily for testing purposes) 154 * @param bool $enablePecl True to enable the use of the PeclUuidTimeGenerator 155 * to generate version 1 UUIDs 156 */ 157 public function __construct( 158 bool $useGuids = false, 159 bool $force32Bit = false, 160 bool $forceNoBigNumber = false, 161 bool $ignoreSystemNode = false, 162 bool $enablePecl = false 163 ) { 164 $this->disableBigNumber = $forceNoBigNumber; 165 $this->disable64Bit = $force32Bit; 166 $this->ignoreSystemNode = $ignoreSystemNode; 167 $this->enablePecl = $enablePecl; 168 169 $this->setCalculator(new BrickMathCalculator()); 170 $this->builder = $this->buildUuidBuilder($useGuids); 171 $this->codec = $this->buildCodec($useGuids); 172 $this->nodeProvider = $this->buildNodeProvider(); 173 $this->nameGenerator = $this->buildNameGenerator(); 174 $this->randomGenerator = $this->buildRandomGenerator(); 175 $this->setTimeProvider(new SystemTimeProvider()); 176 $this->setDceSecurityProvider(new SystemDceSecurityProvider()); 177 $this->validator = new GenericValidator(); 178 } 179 180 /** 181 * Returns the builder configured for this environment 182 */ 183 public function getBuilder(): UuidBuilderInterface 184 { 185 return $this->builder; 186 } 187 188 /** 189 * Returns the calculator configured for this environment 190 */ 191 public function getCalculator(): CalculatorInterface 192 { 193 return $this->calculator; 194 } 195 196 /** 197 * Returns the codec configured for this environment 198 */ 199 public function getCodec(): CodecInterface 200 { 201 return $this->codec; 202 } 203 204 /** 205 * Returns the DCE Security generator configured for this environment 206 */ 207 public function getDceSecurityGenerator(): DceSecurityGeneratorInterface 208 { 209 return $this->dceSecurityGenerator; 210 } 211 212 /** 213 * Returns the name generator configured for this environment 214 */ 215 public function getNameGenerator(): NameGeneratorInterface 216 { 217 return $this->nameGenerator; 218 } 219 220 /** 221 * Returns the node provider configured for this environment 222 */ 223 public function getNodeProvider(): NodeProviderInterface 224 { 225 return $this->nodeProvider; 226 } 227 228 /** 229 * Returns the number converter configured for this environment 230 */ 231 public function getNumberConverter(): NumberConverterInterface 232 { 233 return $this->numberConverter; 234 } 235 236 /** 237 * Returns the random generator configured for this environment 238 */ 239 public function getRandomGenerator(): RandomGeneratorInterface 240 { 241 return $this->randomGenerator; 242 } 243 244 /** 245 * Returns the time converter configured for this environment 246 */ 247 public function getTimeConverter(): TimeConverterInterface 248 { 249 return $this->timeConverter; 250 } 251 252 /** 253 * Returns the time generator configured for this environment 254 */ 255 public function getTimeGenerator(): TimeGeneratorInterface 256 { 257 return $this->timeGenerator; 258 } 259 260 /** 261 * Returns the validator configured for this environment 262 */ 263 public function getValidator(): ValidatorInterface 264 { 265 return $this->validator; 266 } 267 268 /** 269 * Sets the calculator to use in this environment 270 */ 271 public function setCalculator(CalculatorInterface $calculator): void 272 { 273 $this->calculator = $calculator; 274 $this->numberConverter = $this->buildNumberConverter($calculator); 275 $this->timeConverter = $this->buildTimeConverter($calculator); 276 277 if (isset($this->timeProvider)) { 278 $this->timeGenerator = $this->buildTimeGenerator($this->timeProvider); 279 } 280 } 281 282 /** 283 * Sets the DCE Security provider to use in this environment 284 */ 285 public function setDceSecurityProvider(DceSecurityProviderInterface $dceSecurityProvider): void 286 { 287 $this->dceSecurityGenerator = $this->buildDceSecurityGenerator($dceSecurityProvider); 288 } 289 290 /** 291 * Sets the node provider to use in this environment 292 */ 293 public function setNodeProvider(NodeProviderInterface $nodeProvider): void 294 { 295 $this->nodeProvider = $nodeProvider; 296 $this->timeGenerator = $this->buildTimeGenerator($this->timeProvider); 297 } 298 299 /** 300 * Sets the time provider to use in this environment 301 */ 302 public function setTimeProvider(TimeProviderInterface $timeProvider): void 303 { 304 $this->timeProvider = $timeProvider; 305 $this->timeGenerator = $this->buildTimeGenerator($timeProvider); 306 } 307 308 /** 309 * Set the validator to use in this environment 310 */ 311 public function setValidator(ValidatorInterface $validator): void 312 { 313 $this->validator = $validator; 314 } 315 316 /** 317 * Returns a codec configured for this environment 318 * 319 * @param bool $useGuids Whether to build UUIDs using the GuidStringCodec 320 */ 321 private function buildCodec(bool $useGuids = false): CodecInterface 322 { 323 if ($useGuids) { 324 return new GuidStringCodec($this->builder); 325 } 326 327 return new StringCodec($this->builder); 328 } 329 330 /** 331 * Returns a DCE Security generator configured for this environment 332 */ 333 private function buildDceSecurityGenerator( 334 DceSecurityProviderInterface $dceSecurityProvider 335 ): DceSecurityGeneratorInterface { 336 return new DceSecurityGenerator( 337 $this->numberConverter, 338 $this->timeGenerator, 339 $dceSecurityProvider 340 ); 341 } 342 343 /** 344 * Returns a node provider configured for this environment 345 */ 346 private function buildNodeProvider(): NodeProviderInterface 347 { 348 if ($this->ignoreSystemNode) { 349 return new RandomNodeProvider(); 350 } 351 352 return new FallbackNodeProvider(new NodeProviderCollection([ 353 new SystemNodeProvider(), 354 new RandomNodeProvider(), 355 ])); 356 } 357 358 /** 359 * Returns a number converter configured for this environment 360 */ 361 private function buildNumberConverter(CalculatorInterface $calculator): NumberConverterInterface 362 { 363 return new GenericNumberConverter($calculator); 364 } 365 366 /** 367 * Returns a random generator configured for this environment 368 */ 369 private function buildRandomGenerator(): RandomGeneratorInterface 370 { 371 if ($this->enablePecl) { 372 return new PeclUuidRandomGenerator(); 373 } 374 375 return (new RandomGeneratorFactory())->getGenerator(); 376 } 377 378 /** 379 * Returns a time generator configured for this environment 380 * 381 * @param TimeProviderInterface $timeProvider The time provider to use with 382 * the time generator 383 */ 384 private function buildTimeGenerator(TimeProviderInterface $timeProvider): TimeGeneratorInterface 385 { 386 if ($this->enablePecl) { 387 return new PeclUuidTimeGenerator(); 388 } 389 390 return (new TimeGeneratorFactory( 391 $this->nodeProvider, 392 $this->timeConverter, 393 $timeProvider 394 ))->getGenerator(); 395 } 396 397 /** 398 * Returns a name generator configured for this environment 399 */ 400 private function buildNameGenerator(): NameGeneratorInterface 401 { 402 if ($this->enablePecl) { 403 return new PeclUuidNameGenerator(); 404 } 405 406 return (new NameGeneratorFactory())->getGenerator(); 407 } 408 409 /** 410 * Returns a time converter configured for this environment 411 */ 412 private function buildTimeConverter(CalculatorInterface $calculator): TimeConverterInterface 413 { 414 $genericConverter = new GenericTimeConverter($calculator); 415 416 if ($this->is64BitSystem()) { 417 return new PhpTimeConverter($calculator, $genericConverter); 418 } 419 420 return $genericConverter; 421 } 422 423 /** 424 * Returns a UUID builder configured for this environment 425 * 426 * @param bool $useGuids Whether to build UUIDs using the GuidStringCodec 427 */ 428 private function buildUuidBuilder(bool $useGuids = false): UuidBuilderInterface 429 { 430 if ($useGuids) { 431 return new GuidBuilder($this->numberConverter, $this->timeConverter); 432 } 433 434 /** @psalm-suppress ImpureArgument */ 435 return new FallbackBuilder(new BuilderCollection([ 436 new Rfc4122UuidBuilder($this->numberConverter, $this->timeConverter), 437 new NonstandardUuidBuilder($this->numberConverter, $this->timeConverter), 438 ])); 439 } 440 441 /** 442 * Returns true if the PHP build is 64-bit 443 */ 444 private function is64BitSystem(): bool 445 { 446 return PHP_INT_SIZE === 8 && !$this->disable64Bit; 447 } 448} 449