Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1482,3 +1482,22 @@ The powerful `retrieve()` method, which allows for easy access to nested propert
```php
$secretConfig->retrieve('database', 'credentials', 'username');
```

# MagicObject Version 3.22.0

## What's New

1. **UUID Generator**
Added a native UUID generator that produces standards-compliant UUID values, suitable for distributed systems and cross-database compatibility.

2. **Time-Based ID Generator**
Introduced a time-based ID generator that creates sortable, time-ordered identifiers, improving indexing performance and data traceability.

## What's Changed

1. **Default Primary Key Generation**
The default primary key generation strategy for `VARCHAR` columns has been changed to use the **time-based ID generator**, replacing the previous approach.

2. **Improved UUID Implementation**
Replaced the legacy unique ID generation based on PHP’s `uniqid()` function with a **real UUID implementation**, ensuring better uniqueness guarantees and compliance with UUID standards.

60 changes: 60 additions & 0 deletions src/Database/PicoDatabase.php
Original file line number Diff line number Diff line change
Expand Up @@ -1257,6 +1257,66 @@ public function generateNewId()
return sprintf('%s%s', $uuid, $random);
}

/**
* Generate a random UUID (Universally Unique Identifier) version 4.
*
* This function creates a 128-bit UUID using random bytes and applies
* the proper version (4) and variant (RFC 4122) bits. The result is
* formatted as a canonical string representation:
* xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
*
* Example output:
* ad271d69-6c5a-4002-b2d2-3e0f84f7dfa3
*
* @return string A UUID v4 string in standard format.
*/
public function generateUUID() {
// Generate 16 bytes (128 bit) random data
$data = random_bytes(16);

// Set versi ke 0100 (UUID v4)
$data[6] = chr((ord($data[6]) & 0x0f) | 0x40);
// Set variant ke 10xxxxxx
$data[8] = chr((ord($data[8]) & 0x3f) | 0x80);

// Format ke string UUID
return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4));
}

/**
* Generates a unique hexadecimal ID based on the current epoch time in nanoseconds
* combined with a 3-hex-digit random suffix.
*
* The ID consists of:
* - A 17-character hexadecimal timestamp derived from microtime()
* - A 3-character hexadecimal random value
*
* @return string Unique hexadecimal identifier
*/
public function generateTimeBasedId()
{
// Get microtime as "microseconds seconds"
$microtimeParts = explode(' ', microtime());

// Format microseconds to 9 decimal places
$microsecondsFormatted = sprintf('%11.9f', $microtimeParts[0]);

// Split seconds and fractional microseconds
$microsecondsParts = explode('.', $microsecondsFormatted);

// Combine seconds and fractional part into a nanosecond-like integer string
$epochNanoString = sprintf('%d%+9s', $microtimeParts[1], $microsecondsParts[1]);

// Convert the timestamp to a fixed-length hexadecimal string
$timestampHex = sprintf('%017x', (int) $epochNanoString);

// Generate a 3-hex-digit random value
$randomHex = sprintf('%03x', mt_rand(0, 0xFFF));

// Concatenate timestamp and random suffix
return $timestampHex . $randomHex;
}

/**
* Get the last inserted ID.
*
Expand Down
9 changes: 9 additions & 0 deletions src/Database/PicoDatabasePersistence.php
Original file line number Diff line number Diff line change
Expand Up @@ -1143,6 +1143,15 @@ private function setGeneratedValue($prop, $strategy, $firstCall)
$this->generatedValue = true;
}
}
else if(stripos($strategy, "TIMEBASED") !== false)
{
if($firstCall && ($this->object->get($prop) == null || $this->object->get($prop) == "") && !$this->generatedValue)
{
$generatedValue = $this->database->generateTimeBasedId();
$this->object->set($prop, $generatedValue);
$this->generatedValue = true;
}
}
else if(stripos($strategy, "IDENTITY") !== false)
{
if($firstCall)
Expand Down
2 changes: 1 addition & 1 deletion src/Generator/PicoEntityGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public function createProperty($typeMap, $columnMap, $row, $nonupdatables = null
if (!empty($columnKey) && stripos($columnKey, "PRI") === 0) {
$docs[] = "\t * @Id";
if (stripos($columnExtra, "auto_increment") === false) {
$docs[] = "\t * @GeneratedValue(strategy=GenerationType.UUID)";
$docs[] = "\t * @GeneratedValue(strategy=GenerationType.TIMEBASED)";
}
}

Expand Down