diff --git a/apps/files_versions/lib/Db/VersionEntity.php b/apps/files_versions/lib/Db/VersionEntity.php index 10f1dc8cbba..20102e67602 100644 --- a/apps/files_versions/lib/Db/VersionEntity.php +++ b/apps/files_versions/lib/Db/VersionEntity.php @@ -44,7 +44,7 @@ class VersionEntity extends Entity implements JsonSerializable { public function jsonSerialize(): array { return [ - 'id' => $this->id, + 'id' => $this->getId(), 'file_id' => $this->fileId, 'timestamp' => $this->timestamp, 'size' => $this->size, diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index d71f34469d5..1d1657c47c8 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -78,6 +78,7 @@ return array( 'OCP\\AppFramework\\Db\\IMapperException' => $baseDir . '/lib/public/AppFramework/Db/IMapperException.php', 'OCP\\AppFramework\\Db\\MultipleObjectsReturnedException' => $baseDir . '/lib/public/AppFramework/Db/MultipleObjectsReturnedException.php', 'OCP\\AppFramework\\Db\\QBMapper' => $baseDir . '/lib/public/AppFramework/Db/QBMapper.php', + 'OCP\\AppFramework\\Db\\SnowflakeAwareEntity' => $baseDir . '/lib/public/AppFramework/Db/SnowflakeAwareEntity.php', 'OCP\\AppFramework\\Db\\TTransactional' => $baseDir . '/lib/public/AppFramework/Db/TTransactional.php', 'OCP\\AppFramework\\Http' => $baseDir . '/lib/public/AppFramework/Http.php', 'OCP\\AppFramework\\Http\\Attribute\\ARateLimit' => $baseDir . '/lib/public/AppFramework/Http/Attribute/ARateLimit.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 0f7609d13e1..319755ec364 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -119,6 +119,7 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\AppFramework\\Db\\IMapperException' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Db/IMapperException.php', 'OCP\\AppFramework\\Db\\MultipleObjectsReturnedException' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Db/MultipleObjectsReturnedException.php', 'OCP\\AppFramework\\Db\\QBMapper' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Db/QBMapper.php', + 'OCP\\AppFramework\\Db\\SnowflakeAwareEntity' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Db/SnowflakeAwareEntity.php', 'OCP\\AppFramework\\Db\\TTransactional' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Db/TTransactional.php', 'OCP\\AppFramework\\Http' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http.php', 'OCP\\AppFramework\\Http\\Attribute\\ARateLimit' => __DIR__ . '/../../..' . '/lib/public/AppFramework/Http/Attribute/ARateLimit.php', diff --git a/lib/public/AppFramework/Db/Entity.php b/lib/public/AppFramework/Db/Entity.php index 75dcd3e7766..764b7d92237 100644 --- a/lib/public/AppFramework/Db/Entity.php +++ b/lib/public/AppFramework/Db/Entity.php @@ -13,19 +13,23 @@ use function lcfirst; use function substr; /** - * @method int getId() - * @method void setId(int $id) * @since 7.0.0 * @psalm-consistent-constructor */ abstract class Entity { - /** @var int $id */ - public $id = null; - + private ?int $id = null; private array $_updatedFields = []; - /** @var array */ + /** @psalm-param $_fieldTypes array */ private array $_fieldTypes = ['id' => 'integer']; + public function setId($id): void { + $this->id = $id; + } + + public function getId(): ?int { + return $this->id; + } + /** * Simple alternative constructor for building entities from a request * @param array $params the array which was obtained via $this->params('key') @@ -64,7 +68,7 @@ abstract class Entity { /** - * @return array with attribute and type + * @return array with attribute and type * @since 7.0.0 */ public function getFieldTypes(): array { @@ -266,8 +270,8 @@ abstract class Entity { * that value once its being returned from the database * * @param string $fieldName the name of the attribute - * @param \OCP\DB\Types::* $type the type which will be used to match a cast - * @since 31.0.0 Parameter $type is now restricted to {@see \OCP\DB\Types} constants. The formerly accidentally supported types 'int'|'bool'|'double' are mapped to Types::INTEGER|Types::BOOLEAN|Types::FLOAT accordingly. + * @param Types::* $type the type which will be used to match a cast + * @since 31.0.0 Parameter $type is now restricted to {@see Types} constants. The formerly accidentally supported types 'int'|'bool'|'double' are mapped to Types::INTEGER|Types::BOOLEAN|Types::FLOAT accordingly. * @since 7.0.0 */ protected function addType(string $fieldName, string $type): void { diff --git a/lib/public/AppFramework/Db/QBMapper.php b/lib/public/AppFramework/Db/QBMapper.php index d80bb5aec8b..9722b0c94ad 100644 --- a/lib/public/AppFramework/Db/QBMapper.php +++ b/lib/public/AppFramework/Db/QBMapper.php @@ -112,13 +112,17 @@ abstract class QBMapper { $qb->setValue($column, $qb->createNamedParameter($value, $type)); } - $qb->executeStatement(); - - if ($entity->id === null) { + if ($entity instanceof SnowflakeAwareEntity) { + /** @psalm-suppress DocblockTypeContradiction */ + $entity->setId(); + $qb->executeStatement(); + } elseif ($entity->getId() === null) { + $qb->executeStatement(); // When autoincrement is used id is always an int $entity->setId($qb->getLastInsertId()); + } else { + $qb->executeStatement(); } - return $entity; } diff --git a/lib/public/AppFramework/Db/SnowflakeAwareEntity.php b/lib/public/AppFramework/Db/SnowflakeAwareEntity.php new file mode 100644 index 00000000000..a74fbee1e92 --- /dev/null +++ b/lib/public/AppFramework/Db/SnowflakeAwareEntity.php @@ -0,0 +1,56 @@ + */ + private array $_fieldTypes = ['id' => Types::STRING]; + + /** + * Automatically creates a snowflake ID + */ + #[\Override] + public function setId($id = null): void { + if ($this->id === null) { + $this->id = Server::get(ISnowflakeGenerator::class)->nextId(); + $this->markFieldUpdated('id'); + } + } + + public function getCreatedAt(): ?\DateTimeImmutable { + return $this->getSnowflake()?->getCreatedAt(); + } + + public function getSnowflake(): ?Snowflake { + if ($this->id === null) { + return null; + } + + if ($this->snowflake === null) { + $this->snowflake = Server::get(ISnowflakeDecoder::class)->decode($this->id); + } + + return $this->snowflake; + } +}