Skip to content

Commit

Permalink
Unique key for DataObject
Browse files Browse the repository at this point in the history
  • Loading branch information
mfendeksilverstripe committed Feb 9, 2020
1 parent dcb7e2f commit 9761a24
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 2 deletions.
39 changes: 37 additions & 2 deletions src/ORM/DataObject.php
Original file line number Diff line number Diff line change
Expand Up @@ -3236,9 +3236,10 @@ public static function get_one($callerClass = null, $filter = "", $cache = true,
if ($callerClass === self::class) {
throw new InvalidArgumentException('DataObject::get_one() cannot query non-subclass DataObject directly');
}
$SNG = singleton($callerClass);

$cacheComponents = array($filter, $orderBy, $SNG->extend('cacheKeyComponent'));
/** @var DataObject $singleton */
$singleton = singleton($callerClass);
$cacheComponents = [$filter, $orderBy, $singleton->getCacheKeyComponent()];
$cacheKey = md5(serialize($cacheComponents));

$item = null;
Expand Down Expand Up @@ -4209,6 +4210,35 @@ public function mergeRelatedObjects($list, $items)
return $added;
}

/**
* Generate a unique key for data object
* the unique key uses the @see DataObject::getCacheKeyComponent() extension point so unique key modifiers
* such as versioned or fluent are covered
* i.e. same data object in different stages or different locales will produce different unique key
*
* recommended use:
* - when you need unique key for caching purposes
* - when you need unique id on the front end (for example JavaScript needs to target specific element)
*
* @return string
*/
public function getUniqueKey(): string
{
// extract class name (remove namespaces)
$classSegments = explode('\\', $this->ClassName);

if (count($classSegments) === 0) {
return '';
}

$class = array_pop($classSegments);
$cacheKeys = $this->getCacheKeyComponent();
$cacheKeys = json_encode($cacheKeys);
$hash = md5(sprintf('%s-%s-%d', $cacheKeys, $this->ClassName, $this->ID));

return sprintf('ss-%s-%d-%s', $class, $this->ID, $hash);
}

/**
* Merge single object into a list, but ensures that existing objects are not
* re-added.
Expand All @@ -4234,4 +4264,9 @@ protected function mergeRelatedObject($list, $added, $item)
$this->mergeRelatedObject($list, $added, $joined);
}
}

protected function getCacheKeyComponent(): array
{
return $this->extend('cacheKeyComponent');
}
}
22 changes: 22 additions & 0 deletions tests/php/ORM/DataObjectTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2536,4 +2536,26 @@ public function testShallowRecursiveWrite()
'Root is 2 step remove from grand children. It was not written on a shallow recursive write.'
);
}

/**
* @param string $identifier
* @param string $class
* @param string $expected
* @dataProvider uniqueKeysProvider
*/
public function testUniqueKey(string $identifier, string $class, string $expected): void
{
$object = $this->objFromFixture($class, $identifier);
$this->assertEquals($expected, $object->getUniqueKey());
}

public function uniqueKeysProvider(): array
{
return [
['team1', DataObjectTest\Team::class, 'ss-Team-1-a4ec237d518051effd373f90dad9a1e2'],
['team2', DataObjectTest\Team::class, 'ss-Team-2-69de0ff334cf4687a528c2dbbe198d7d'],
['captain1', DataObjectTest\Player::class, 'ss-Player-1-8fdb4b4c871b413daa017f89e43aadd5'],
['captain2', DataObjectTest\Player::class, 'ss-Player-2-096c7afa2396936b75e045a27b708f8b'],
];
}
}

0 comments on commit 9761a24

Please sign in to comment.