| 1 |  |  | <?php | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | namespace LeKoala\Uuid; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  | use Ramsey\Uuid\Uuid; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  | use SilverStripe\ORM\DB; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  | use InvalidArgumentException; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  | use SilverStripe\Forms\FieldList; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  | use SilverStripe\Forms\ReadonlyField; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  | use SilverStripe\ORM\DataObject; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  | use Tuupola\Base62Proxy as Base62; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  | use SilverStripe\ORM\DataExtension; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  | use SilverStripe\ORM\DataObjectSchema; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  | class UuidExtension extends DataExtension | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  | { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |     const UUID_BINARY_FORMAT = 'binary'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |     const UUID_STRING_FORMAT = 'string'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |     const UUID_BASE62_FORMAT = 'base62'; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |     private static $db = [ | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |         "Uuid" => DBUuid::class, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  |     ]; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  |     private static $indexes = [ | 
                            
                    |  |  |  | 
                                                                                        
                                                                                     | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  |         "Uuid" => true, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  |     ]; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |      * Assign a new uuid to this record. This will overwrite any existing uuid. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  |      * @param bool $check Check if the uuid is already taken | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |      * @return string The new uuid | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  |     public function assignNewUuid($check = true) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |         $uuid = Uuid::uuid4(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 |  |  |         if ($check) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |             $schema = DataObjectSchema::create(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 |  |  |             $table = $schema->tableForField(get_class($this->owner), 'Uuid'); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |             do { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 |  |  |                 $this->owner->Uuid = $uuid->getBytes(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |                 // If we have something, keep checking | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 |  |  |                 $check = DB::prepared_query('SELECT count(ID) FROM ' . $table . ' WHERE Uuid = ?', [$this->owner->Uuid])->value() > 0; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |             } while ($check); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 |  |  |         } else { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |             $this->owner->Uuid = $uuid->getBytes(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |         return $this->owner->Uuid; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |      * Get a record by its uuid | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |      * @param string $class The class | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |      * @param string $uuid The uuid value | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |      * @param string $format Any UUID_XXXX_FORMAT constant or string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |      * @return DataObject|false The DataObject or false if no record is found or format invalid | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |     public static function getByUuid($class, $value, $format = null) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |         // Guess format from value | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |         if ($format === null) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  |             try { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |                 $format = self::getUuidFormat($value); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |             } catch (InvalidArgumentException $ex) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |                 $format = null; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |         // Convert format to bytes for query | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |         switch ($format) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  |             case self::UUID_BASE62_FORMAT: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |                 $uuid = Uuid::fromBytes(Base62::decode($value)); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  |                 break; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |             case self::UUID_STRING_FORMAT: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  |                 $uuid = Uuid::fromString($value); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 |  |  |                 break; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 |  |  |             case self::UUID_BINARY_FORMAT: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 |  |  |                 $uuid = Uuid::fromBytes($value); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  |                 break; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |             default: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |                 return false; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 |  |  |         // Fetch the first record and disable subsite filter in a similar way as asking by ID | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |         $q = $class::get()->filter('Uuid', $uuid->getBytes())->setDataQueryParam('Subsite.filter', false); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |         return $q->first(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 |  |  |      * Guess uuid format based on strlen | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 |  |  |      * @param mixed $value | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  |      * @return string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |      * @throws InvalidArgumentException | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 |  |  |     public static function getUuidFormat($value) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 |  |  |         $len = strlen((string)$value); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 |  |  |         if ($len == 36) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 |  |  |             // d84560c8-134f-11e6-a1e2-34363bd26dae => 36 chars | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 |  |  |             return self::UUID_STRING_FORMAT; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  |         } elseif ($len > 20 && $len < 24) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 |  |  |             // 6a630O1jrtMjCrQDyG3D3O => 22 chars (in theory, because sometimes it's different) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |             return self::UUID_BASE62_FORMAT; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 |  |  |         } elseif ($len == 16) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 |  |  |             return self::UUID_BINARY_FORMAT; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 |  |  |         throw new InvalidArgumentException("$value does not seem to be a valid uuid"); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 |  |  |      * Return a uuid suitable for an URL, like an URLSegment | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 |  |  |      * | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 |  |  |      * @return string | 
            
                                                                                                            
                            
            
                                    
            
            
                | 116 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 117 |  |  |     public function UuidSegment() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 118 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 119 |  |  |         // assign on the fly | 
            
                                                                                                            
                            
            
                                    
            
            
                | 120 |  |  |         if (!$this->owner->Uuid) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 121 |  |  |             $uuid = $this->assignNewUuid(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 122 |  |  |             // Make a quick write without using orm | 
            
                                                                                                            
                            
            
                                    
            
            
                | 123 |  |  |             if ($this->owner->ID) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 124 |  |  |                 $schema = new DataObjectSchema; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 125 |  |  |                 $table = $schema->tableName(get_class($this->owner)); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 126 |  |  |                 DB::prepared_query("UPDATE $table SET Uuid = ? WHERE ID = ?", [$uuid, $this->owner->ID]); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 127 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 128 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 129 |  |  |         return $this->owner->dbObject('Uuid')->Base62(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 130 |  |  |     } | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 131 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 132 |  |  |     public function updateCMSFields(FieldList $fields) | 
            
                                                                        
                            
            
                                    
            
            
                | 133 |  |  |     { | 
            
                                                                        
                            
            
                                    
            
            
                | 134 |  |  |         if (DBUuid::config()->show_cms_field) { | 
            
                                                                        
                            
            
                                    
            
            
                | 135 |  |  |             $firstField = $fields->dataFieldNames()[0] ?? null; | 
            
                                                                        
                            
            
                                    
            
            
                | 136 |  |  |             $fields->addFieldToTab('Root.Main', ReadonlyField::create('UuidNice', 'Uuid', $this->owner->dbObject('Uuid')->Nice()), $firstField); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 137 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 138 |  |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 139 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 140 |  |  |     public function onBeforeWrite() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 141 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 142 |  |  |         parent::onBeforeWrite(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 143 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 144 |  |  |         if (!$this->owner->Uuid) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 145 |  |  |             $this->assignNewUuid(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 146 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 147 |  |  |     } | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 148 |  |  | } | 
            
                                                        
            
                                    
            
            
                | 149 |  |  |  |