parent
13bfbbe528
commit
eb40f1df49
10 changed files with 388 additions and 44 deletions
|
@ -24,7 +24,8 @@
|
|||
"phpstan/phpstan": "^1.11",
|
||||
"phpstan/phpstan-strict-rules": "^1.6",
|
||||
"phpstan/extension-installer": "^1.3",
|
||||
"pestphp/pest": "^2.34"
|
||||
"pestphp/pest": "^2.34",
|
||||
"mockery/mockery": "^1.6"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
|
|
136
composer.lock
generated
136
composer.lock
generated
|
@ -4,7 +4,7 @@
|
|||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "e57b9ac60bbc4cb4066c8cefa8d6d1c4",
|
||||
"content-hash": "04633c6e5d6a281e4f5cf33a8246d0d3",
|
||||
"packages": [
|
||||
{
|
||||
"name": "doctrine/collections",
|
||||
|
@ -2097,6 +2097,57 @@
|
|||
],
|
||||
"time": "2023-11-03T12:00:00+00:00"
|
||||
},
|
||||
{
|
||||
"name": "hamcrest/hamcrest-php",
|
||||
"version": "v2.0.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/hamcrest/hamcrest-php.git",
|
||||
"reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/8c3d0a3f6af734494ad8f6fbbee0ba92422859f3",
|
||||
"reference": "8c3d0a3f6af734494ad8f6fbbee0ba92422859f3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": "^5.3|^7.0|^8.0"
|
||||
},
|
||||
"replace": {
|
||||
"cordoval/hamcrest-php": "*",
|
||||
"davedevelopment/hamcrest-php": "*",
|
||||
"kodova/hamcrest-php": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/php-file-iterator": "^1.4 || ^2.0",
|
||||
"phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"hamcrest"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"description": "This is the PHP port of Hamcrest Matchers",
|
||||
"keywords": [
|
||||
"test"
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/hamcrest/hamcrest-php/issues",
|
||||
"source": "https://github.com/hamcrest/hamcrest-php/tree/v2.0.1"
|
||||
},
|
||||
"time": "2020-07-09T08:09:16+00:00"
|
||||
},
|
||||
{
|
||||
"name": "jean85/pretty-package-versions",
|
||||
"version": "2.0.6",
|
||||
|
@ -2185,6 +2236,89 @@
|
|||
],
|
||||
"time": "2024-05-04T18:26:43+00:00"
|
||||
},
|
||||
{
|
||||
"name": "mockery/mockery",
|
||||
"version": "1.6.12",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/mockery/mockery.git",
|
||||
"reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/mockery/mockery/zipball/1f4efdd7d3beafe9807b08156dfcb176d18f1699",
|
||||
"reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"hamcrest/hamcrest-php": "^2.0.1",
|
||||
"lib-pcre": ">=7.0",
|
||||
"php": ">=7.3"
|
||||
},
|
||||
"conflict": {
|
||||
"phpunit/phpunit": "<8.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^8.5 || ^9.6.17",
|
||||
"symplify/easy-coding-standard": "^12.1.14"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"files": [
|
||||
"library/helpers.php",
|
||||
"library/Mockery.php"
|
||||
],
|
||||
"psr-4": {
|
||||
"Mockery\\": "library/Mockery"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Pádraic Brady",
|
||||
"email": "padraic.brady@gmail.com",
|
||||
"homepage": "https://github.com/padraic",
|
||||
"role": "Author"
|
||||
},
|
||||
{
|
||||
"name": "Dave Marshall",
|
||||
"email": "dave.marshall@atstsolutions.co.uk",
|
||||
"homepage": "https://davedevelopment.co.uk",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "Nathanael Esayeas",
|
||||
"email": "nathanael.esayeas@protonmail.com",
|
||||
"homepage": "https://github.com/ghostwriter",
|
||||
"role": "Lead Developer"
|
||||
}
|
||||
],
|
||||
"description": "Mockery is a simple yet flexible PHP mock object framework",
|
||||
"homepage": "https://github.com/mockery/mockery",
|
||||
"keywords": [
|
||||
"BDD",
|
||||
"TDD",
|
||||
"library",
|
||||
"mock",
|
||||
"mock objects",
|
||||
"mockery",
|
||||
"stub",
|
||||
"test",
|
||||
"test double",
|
||||
"testing"
|
||||
],
|
||||
"support": {
|
||||
"docs": "https://docs.mockery.io/",
|
||||
"issues": "https://github.com/mockery/mockery/issues",
|
||||
"rss": "https://github.com/mockery/mockery/releases.atom",
|
||||
"security": "https://github.com/mockery/mockery/security/advisories",
|
||||
"source": "https://github.com/mockery/mockery"
|
||||
},
|
||||
"time": "2024-05-16T03:13:13+00:00"
|
||||
},
|
||||
{
|
||||
"name": "myclabs/deep-copy",
|
||||
"version": "1.11.1",
|
||||
|
|
|
@ -4,18 +4,23 @@ namespace Lubiana\DoctrineUlid\IdGenerator;
|
|||
|
||||
use Doctrine\ORM\EntityManagerInterface;
|
||||
use Doctrine\ORM\Id\AbstractIdGenerator;
|
||||
use Override;
|
||||
use Symfony\Component\Uid\Factory\UlidFactory;
|
||||
use Symfony\Component\Uid\Ulid;
|
||||
|
||||
final class UlidGenerator extends AbstractIdGenerator
|
||||
{
|
||||
public function __construct( private readonly ?UlidFactory $factory = null ){}
|
||||
public function generateId(EntityManagerInterface $em, ?object $entity): mixed
|
||||
public function __construct(
|
||||
private readonly UlidFactory|null $factory = null
|
||||
) {}
|
||||
|
||||
#[Override]
|
||||
public function generateId(EntityManagerInterface $em, object|null $entity): mixed
|
||||
{
|
||||
if ($this->factory !== null) {
|
||||
if ($this->factory instanceof UlidFactory) {
|
||||
return $this->factory->create();
|
||||
}
|
||||
|
||||
return new Ulid();
|
||||
return new Ulid;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,17 +6,21 @@ use Doctrine\DBAL\Platforms\AbstractPlatform;
|
|||
use Doctrine\DBAL\Types\Exception\InvalidType;
|
||||
use Doctrine\DBAL\Types\Exception\ValueNotConvertible;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use InvalidArgumentException;
|
||||
use Override;
|
||||
use Symfony\Component\Uid\Ulid;
|
||||
|
||||
use function is_string;
|
||||
|
||||
final class UlidType extends Type
|
||||
{
|
||||
public const NAME = 'ulid';
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getSQLDeclaration(array $column, AbstractPlatform $platform): string
|
||||
{
|
||||
#[Override]
|
||||
public function getSQLDeclaration(
|
||||
array $column,
|
||||
AbstractPlatform $platform,
|
||||
): string {
|
||||
if ($this->hasNativeGuidType($platform)) {
|
||||
return $platform->getGuidTypeDeclarationSQL($column);
|
||||
}
|
||||
|
@ -27,26 +31,35 @@ final class UlidType extends Type
|
|||
]);
|
||||
}
|
||||
|
||||
public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?Ulid
|
||||
{
|
||||
#[Override]
|
||||
public function convertToPHPValue(
|
||||
mixed $value,
|
||||
AbstractPlatform $platform,
|
||||
): Ulid|null {
|
||||
if ($value instanceof Ulid || $value === null) {
|
||||
return $value;
|
||||
}
|
||||
if (!is_string($value)) {
|
||||
|
||||
if (! is_string($value)) {
|
||||
throw InvalidType::new($value, self::NAME, ['null', 'string', self::class]);
|
||||
}
|
||||
|
||||
try {
|
||||
return Ulid::fromString($value);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
} catch (InvalidArgumentException $e) {
|
||||
throw ValueNotConvertible::new($value, self::NAME, null, $e);
|
||||
}
|
||||
}
|
||||
|
||||
public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): ?string
|
||||
{
|
||||
$toStringFunc = fn (Ulid $v) => $v->toRfc4122();
|
||||
if (!$this->hasNativeGuidType($platform)) {
|
||||
$toStringFunc = fn (Ulid $v) => $v->toBinary();
|
||||
#[Override]
|
||||
public function convertToDatabaseValue(
|
||||
mixed $value,
|
||||
AbstractPlatform $platform,
|
||||
): string|null {
|
||||
$toStringFunc = static fn(Ulid $v): string => $v->toRfc4122();
|
||||
|
||||
if (! $this->hasNativeGuidType($platform)) {
|
||||
$toStringFunc = static fn(Ulid $v): string => $v->toBinary();
|
||||
}
|
||||
|
||||
if ($value instanceof Ulid) {
|
||||
|
@ -57,18 +70,32 @@ final class UlidType extends Type
|
|||
return null;
|
||||
}
|
||||
|
||||
if (!\is_string($value)) {
|
||||
if (! is_string($value)) {
|
||||
throw InvalidType::new($value, self::NAME, ['null', 'string', self::class]);
|
||||
}
|
||||
|
||||
try {
|
||||
return $toStringFunc(Ulid::fromString($value));
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
} catch (InvalidArgumentException $e) {
|
||||
throw ValueNotConvertible::new($value, self::NAME, null, $e);
|
||||
}
|
||||
}
|
||||
|
||||
private function hasNativeGuidType(AbstractPlatform $platform): bool
|
||||
{
|
||||
return $platform->getGuidTypeDeclarationSQL([]) !== $platform->getStringTypeDeclarationSQL(['fixed' => true, 'length' => 36]);
|
||||
return $platform->getGuidTypeDeclarationSQL([]) !== $platform->getStringTypeDeclarationSQL([
|
||||
'fixed' => true,
|
||||
'length' => 36,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
public static function register(): void
|
||||
{
|
||||
if (Type::hasType(self::NAME)) {
|
||||
Type::overrideType(self::NAME, self::class);
|
||||
return;
|
||||
}
|
||||
|
||||
Type::addType(self::NAME, self::class);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
test(
|
||||
'example',
|
||||
function (): void {
|
||||
expect(true)->toBeTrue();
|
||||
},
|
||||
);
|
|
@ -1,5 +1,6 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
use Mockery\MockInterface;
|
||||
use Tests\TestCase;
|
||||
|
||||
/*
|
||||
|
@ -24,7 +25,12 @@ uses(TestCase::class)->in('Feature', 'Unit');
|
|||
| global functions to help you to reduce the number of lines of code in your test files.
|
||||
|
|
||||
*/
|
||||
function something(): void
|
||||
/**
|
||||
* @template T of object
|
||||
* @param class-string<T> $className
|
||||
* @return MockInterface&T
|
||||
*/
|
||||
function createMock(string $className): MockInterface
|
||||
{
|
||||
// ..
|
||||
return Mockery::mock($className);
|
||||
}
|
||||
|
|
|
@ -2,9 +2,15 @@
|
|||
|
||||
namespace Tests;
|
||||
|
||||
use Lubiana\DoctrineUlid\Types\UlidType;
|
||||
use Override;
|
||||
use PHPUnit\Framework\TestCase as BaseTestCase;
|
||||
|
||||
abstract class TestCase extends BaseTestCase
|
||||
{
|
||||
//
|
||||
#[Override]
|
||||
protected function setUp(): void
|
||||
{
|
||||
UlidType::register();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
test(
|
||||
'example',
|
||||
function (): void {
|
||||
expect(true)->toBeTrue();
|
||||
},
|
||||
);
|
33
tests/Unit/UlidGeneratorTest.php
Normal file
33
tests/Unit/UlidGeneratorTest.php
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
use Doctrine\ORM\EntityManager;
|
||||
use Lubiana\DoctrineUlid\IdGenerator\UlidGenerator;
|
||||
use Symfony\Component\Uid\Factory\UlidFactory;
|
||||
use Symfony\Component\Uid\Ulid;
|
||||
|
||||
test(
|
||||
'UlidGenerator constructs without factory and generate Id',
|
||||
function (): void {
|
||||
$ulidGenerator = new UlidGenerator;
|
||||
$em = createMock(EntityManager::class);
|
||||
$id = $ulidGenerator->generateId($em, null);
|
||||
expect($id)
|
||||
->toBeInstanceOf(Ulid::class);
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
'UlidGenerator constructs with factory and generate Id',
|
||||
function (): void {
|
||||
$factory = Mockery::mock(UlidFactory::class);
|
||||
$ulid = new Ulid;
|
||||
$factory->shouldReceive('create')
|
||||
->andReturn($ulid)
|
||||
->once();
|
||||
$ulidGenerator = new UlidGenerator($factory);
|
||||
$em = Mockery::mock(EntityManager::class);
|
||||
$id = $ulidGenerator->generateId($em, null);
|
||||
expect($id)
|
||||
->toBe($ulid);
|
||||
},
|
||||
);
|
148
tests/Unit/UlidTypeTest.php
Normal file
148
tests/Unit/UlidTypeTest.php
Normal file
|
@ -0,0 +1,148 @@
|
|||
<?php declare(strict_types=1);
|
||||
|
||||
use Doctrine\DBAL\Platforms\PostgreSQLPlatform;
|
||||
use Doctrine\DBAL\Platforms\SQLitePlatform;
|
||||
use Doctrine\DBAL\Types\Exception\InvalidType;
|
||||
use Doctrine\DBAL\Types\Exception\ValueNotConvertible;
|
||||
use Doctrine\DBAL\Types\Type;
|
||||
use Lubiana\DoctrineUlid\Types\UlidType;
|
||||
use Symfony\Component\Uid\Ulid;
|
||||
|
||||
it(
|
||||
'returns correct sql declaration on postgresql',
|
||||
function (): void {
|
||||
$ulidType = Type::getType(UlidType::NAME);
|
||||
$platform = new PostgreSQLPlatform;
|
||||
|
||||
// If platform supports guid type, declaration is guid type.
|
||||
$declaration = $ulidType->getSQLDeclaration([], $platform);
|
||||
expect($declaration)
|
||||
->toBe('UUID');
|
||||
},
|
||||
);
|
||||
|
||||
it(
|
||||
'returns correct sql declaration on sqlite',
|
||||
function (): void {
|
||||
$ulidType = Type::getType(UlidType::NAME);
|
||||
$platform = new SqlitePlatform;
|
||||
|
||||
// If platform supports guid type, declaration is guid type.
|
||||
$declaration = $ulidType->getSQLDeclaration([], $platform);
|
||||
expect($declaration)
|
||||
->toBe('BLOB');
|
||||
},
|
||||
);
|
||||
|
||||
it(
|
||||
'can convert string to a Ulid object',
|
||||
function (): void {
|
||||
$ulidType = Type::getType(UlidType::NAME);
|
||||
$platform = new SQLitePlatform;
|
||||
$stringUlid = '01FGRM9X8ACP5D6HZG9K31D6CZ';
|
||||
$phpValue = $ulidType->convertToPHPValue($stringUlid, $platform);
|
||||
expect(
|
||||
$phpValue,
|
||||
)->toBeInstanceOf(Ulid::class)->and((string) $phpValue)->toBe($stringUlid);
|
||||
},
|
||||
);
|
||||
|
||||
it(
|
||||
'throws if value is not string during conversion to PHP Value',
|
||||
function (): void {
|
||||
$ulidType = Type::getType(UlidType::NAME);
|
||||
$platform = new SQLitePlatform;
|
||||
$nonStringValue = 123;
|
||||
expect(
|
||||
static fn(): mixed
|
||||
=> $ulidType->convertToPHPValue($nonStringValue, $platform),
|
||||
)->toThrow(
|
||||
InvalidType::class,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
it(
|
||||
'throws if value is not a valid Ulid string during conversion to PHP Value',
|
||||
function (): void {
|
||||
$ulidType = Type::getType(UlidType::NAME);
|
||||
$platform = new SQLitePlatform;
|
||||
$invalidUlidString = 'invalid-ulid-string';
|
||||
expect(
|
||||
static fn(): mixed
|
||||
=> $ulidType->convertToPHPValue($invalidUlidString, $platform),
|
||||
)->toThrow(
|
||||
ValueNotConvertible::class,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
it(
|
||||
'can convert Ulid object to database value',
|
||||
function (): void {
|
||||
$ulidType = Type::getType(UlidType::NAME);
|
||||
$platform = new SQLitePlatform;
|
||||
$ulidObject = new Ulid;
|
||||
$databaseValue = $ulidType->convertToDatabaseValue($ulidObject, $platform);
|
||||
expect($databaseValue)
|
||||
->toBe($ulidObject->toBinary());
|
||||
},
|
||||
);
|
||||
|
||||
it(
|
||||
'can convert Ulid string to a database value',
|
||||
function (): void {
|
||||
$ulidType = Type::getType(UlidType::NAME);
|
||||
$platform = new SQLitePlatform;
|
||||
$ulidObject = new Ulid;
|
||||
$ulidBinary = $ulidObject->toBinary();
|
||||
$databaseValue = $ulidType->convertToDatabaseValue(
|
||||
(string) $ulidObject,
|
||||
$platform,
|
||||
);
|
||||
expect($databaseValue)
|
||||
->toBe($ulidBinary);
|
||||
},
|
||||
);
|
||||
|
||||
it(
|
||||
'will return null when value is null',
|
||||
function (): void {
|
||||
$ulidType = Type::getType(UlidType::NAME);
|
||||
$platform = new SQLitePlatform;
|
||||
$nullValue = null;
|
||||
$databaseValue = $ulidType->convertToDatabaseValue($nullValue, $platform);
|
||||
expect($databaseValue)
|
||||
->toBe(null);
|
||||
},
|
||||
);
|
||||
|
||||
it(
|
||||
'throws if value is not string during conversion to Database Value',
|
||||
function (): void {
|
||||
$ulidType = Type::getType(UlidType::NAME);
|
||||
$platform = new SQLitePlatform;
|
||||
$nonStringValue = 123;
|
||||
expect(
|
||||
static fn(): mixed
|
||||
=> $ulidType->convertToDatabaseValue($nonStringValue, $platform),
|
||||
)->toThrow(
|
||||
InvalidType::class,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
it(
|
||||
'throws if value is not a valid Ulid string during conversion to Database Value',
|
||||
function (): void {
|
||||
$ulidType = Type::getType(UlidType::NAME);
|
||||
$platform = new SQLitePlatform;
|
||||
$invalidUlidString = 'invalid-ulid-string';
|
||||
expect(
|
||||
static fn(): mixed
|
||||
=> $ulidType->convertToDatabaseValue($invalidUlidString, $platform),
|
||||
)->toThrow(
|
||||
ValueNotConvertible::class,
|
||||
);
|
||||
},
|
||||
);
|
Loading…
Reference in a new issue