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
41 changes: 10 additions & 31 deletions Monorepo/Benchmark/ProjectingBenchmark.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use Ecotone\Messaging\Config\ConfiguredMessagingSystem;
use Ecotone\Messaging\Config\ModulePackageList;
use Ecotone\Messaging\Config\ServiceConfiguration;
use Ecotone\Modelling\CommandBus;
use Ecotone\Projecting\ProjectionRegistry;
use Ecotone\Test\LicenceTesting;
use Enqueue\Dbal\DbalConnectionFactory;
Expand Down Expand Up @@ -52,7 +53,6 @@ public static function bootEcotone(string $name, array $container, array $namesp
->withSkippedModulePackageNames(ModulePackageList::allPackagesExcept([
ModulePackageList::EVENT_SOURCING_PACKAGE,
ModulePackageList::DBAL_PACKAGE,
ModulePackageList::JMS_CONVERTER_PACKAGE
])),
useCachedVersion: true,
pathToRootCatalog: self::getProjectDir(),
Expand Down Expand Up @@ -154,48 +154,26 @@ private static function executeWithDeletion(ConfiguredMessagingSystem $messaging
], $queryBus->sendWithRouting('product.getPriceChange', $productId), 'Price changes should be projected again after deletion');
}

public function fillEcotone(): void
{
$projection = self::$ecotone->getServiceFromContainer(ProjectionRegistry::class)->get(PriceChangeOverTimeProjectionWithEcotoneProjection::NAME);
public function fill(): void {
$commandBus = self::$ecotone->getCommandBus();
$projection->delete();

self::$expectedProductIds = [];
for ($i = 0; $i < 100; $i++) {
self::$expectedProductIds[] = $productId = Uuid::uuid4()->toString();
$commandBus->send(new RegisterProduct($productId, 100));
$commandBus->send(new ChangePrice($productId, 120));
$commandBus->send(new ChangePrice($productId, 130));
}

$projection->delete();
}

public function fillProoph(): void
{
$projection = self::$prooph->getServiceFromContainer(ProjectionManager::class);
$commandBus = self::$prooph->getCommandBus();
$projection->deleteProjection(PriceChangeOverTimeProjectionWithEcotoneProjection::NAME);

self::$expectedProductIds = [];
for ($i = 0; $i < 100; $i++) {
self::$expectedProductIds[] = $productId = Uuid::uuid4()->toString();
$commandBus->send(new RegisterProduct($productId, 100));
$commandBus->send(new ChangePrice($productId, 120));
$commandBus->send(new ChangePrice($productId, 130));
}

$projection->deleteProjection(PriceChangeOverTimeProjectionWithEcotoneProjection::NAME);
}

#[BeforeMethods(["setUp", "fillEcotone"])]
#[Revs(1), Warmup(0)]
#[BeforeMethods(["setUp", "fill"])]
#[Iterations(1), Warmup(0)]
public function bench_ecotone_projection_backfill(): void
{
$projectionManager = self::$ecotone->getServiceFromContainer(ProjectionRegistry::class)->get(PriceChangeOverTimeProjectionWithEcotoneProjection::NAME);
$projectionManager->delete();
Assert::assertEquals([],
self::$ecotone->getQueryBus()->sendWithRouting('product.getPriceChange', self::$expectedProductIds[0])
);
$projectionManager = self::$ecotone->getServiceFromContainer(ProjectionRegistry::class)->get(PriceChangeOverTimeProjectionWithEcotoneProjection::NAME);
$projectionManager->backfill();
Assert::assertEquals([
new PriceChange(100, 0),
Expand All @@ -206,14 +184,15 @@ public function bench_ecotone_projection_backfill(): void
);
}

#[BeforeMethods(["setUp", "fillProoph"])]
#[Revs(1), Warmup(0)]
#[BeforeMethods(["setUp", "fill"])]
#[Iterations(1), Warmup(0)]
public function bench_prooph_projection_backfill(): void
{
$projectionManager = self::$prooph->getServiceFromContainer(ProjectionManager::class);
$projectionManager->deleteProjection(PriceChangeOverTimeProjection::NAME);
Assert::assertEquals([],
self::$prooph->getQueryBus()->sendWithRouting('product.getPriceChange', self::$expectedProductIds[0])
);
$projectionManager = self::$prooph->getServiceFromContainer(ProjectionManager::class);
$projectionManager->triggerProjection(PriceChangeOverTimeProjection::NAME);
Assert::assertEquals([
new PriceChange(100, 0),
Expand Down
17 changes: 17 additions & 0 deletions Monorepo/ExampleAppEventSourcing/Common/Event/PriceWasChanged.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Monorepo\ExampleAppEventSourcing\Common\Event;

use Ecotone\Messaging\Attribute\Converter;

class PriceWasChanged
{
public function __construct(private string $productId, private float $price) {}
Expand All @@ -15,4 +17,19 @@ public function getPrice(): float
{
return $this->price;
}

#[Converter]
public static function fromArray(array $data): self
{
return new self($data['productId'], $data['price']);
}

#[Converter]
public static function toArray(self $object): array
{
return [
'productId' => $object->productId,
'price' => $object->price,
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

namespace Monorepo\ExampleAppEventSourcing\Common\Event;

use Ecotone\Messaging\Attribute\Converter;

class ProductWasRegistered
{
public function __construct(private string $productId, private float $price) {}
Expand All @@ -15,4 +17,19 @@ public function getPrice(): float
{
return $this->price;
}

#[Converter]
public static function fromArray(array $data): self
{
return new self($data['productId'], $data['price']);
}

#[Converter]
public static function toArray(self $object): array
{
return [
'productId' => $object->productId,
'price' => $object->price,
];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,30 @@
use Ecotone\Messaging\Config\Annotation\AnnotatedDefinitionReference;
use Ecotone\Messaging\Config\Annotation\AnnotationModule;
use Ecotone\Messaging\Config\Configuration;
use Ecotone\Messaging\Config\Container\CompilableBuilder;
use Ecotone\Messaging\Config\Container\Definition;
use Ecotone\Messaging\Config\Container\Reference;
use Ecotone\Messaging\Config\ModulePackageList;
use Ecotone\Messaging\Config\ModuleReferenceSearchService;
use Ecotone\Messaging\Conversion\ConverterBuilder;
use Ecotone\Messaging\Conversion\ConverterReferenceBuilder;
use Ecotone\Messaging\Conversion\ReferenceServiceConverterBuilder;
use Ecotone\Messaging\Conversion\ReferenceServiceConverter;
use Ecotone\Messaging\Conversion\StaticCallConverter;
use Ecotone\Messaging\Handler\InterfaceToCallRegistry;
use Ecotone\Messaging\Support\InvalidArgumentException;

#[ModuleAnnotation]
/**
* licence Apache-2.0
*/
class ConverterModule extends NoExternalConfigurationModule implements AnnotationModule
{
/**
* @var ConverterBuilder[]
*/
private array $converterBuilders = [];

/**
* ConverterModule constructor.
*
* @param array $converterBuilders
* @param CompilableBuilder[] $converterBuilders
*/
private function __construct(array $converterBuilders)
private function __construct(private array $converterBuilders)
{
$this->converterBuilders = $converterBuilders;
}

/**
Expand All @@ -50,12 +48,31 @@ public static function create(AnnotationFinder $annotationRegistrationService, I

foreach ($registrations as $registration) {
$interfaceToCall = $interfaceToCallRegistry->getFor($registration->getClassName(), $registration->getMethodName());
$converterBuilders[] = ReferenceServiceConverterBuilder::create(
AnnotatedDefinitionReference::getReferenceFor($registration),
$registration->getMethodName(),
$interfaceToCall->getFirstParameter()->getTypeDescriptor(),
$interfaceToCall->getReturnType()
);

if (!$interfaceToCall->hasSingleParameter()) {
throw InvalidArgumentException::create("Converter should have only single parameter: {$interfaceToCall}");
}
if ($interfaceToCall->getReturnType()->isVoid()) {
throw InvalidArgumentException::create("Converter cannot have void return type: {$interfaceToCall}");
}
if ($interfaceToCall->getReturnType()->isUnionType()) {
throw InvalidArgumentException::create("Converter cannot have union type as parameter: {$interfaceToCall}");
}
if ($interfaceToCall->isStaticallyCalled()) {
$converterBuilders[] = new Definition(StaticCallConverter::class, [
$interfaceToCall->getInterfaceName(),
$interfaceToCall->getMethodName(),
$interfaceToCall->getFirstParameter()->getTypeDescriptor(),
$interfaceToCall->getReturnType(),
]);
} else {
$converterBuilders[] = new Definition(ReferenceServiceConverter::class, [
new Reference(AnnotatedDefinitionReference::getReferenceFor($registration)),
$registration->getMethodName(),
$interfaceToCall->getFirstParameter()->getTypeDescriptor(),
$interfaceToCall->getReturnType(),
]);
}
}

$registrations = $annotationRegistrationService->findAnnotatedClasses(MediaTypeConverter::class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,53 +19,16 @@
*/
class ReferenceServiceConverter implements Converter
{
private object $object;
private string $method;
private Type $sourceType;
private Type $targetType;

/**
* ReferenceConverter constructor.
* @param object $object
* @param string $method
* @param Type $sourceType
* @param Type $targetType
* @throws \Ecotone\Messaging\MessagingException
*/
public function __construct($object, string $method, Type $sourceType, Type $targetType)
{
Assert::isObject($object, '');
$this->object = $object;
$this->method = $method;
$this->sourceType = $sourceType;
$this->targetType = $targetType;

$reflectionMethod = new ReflectionMethod($object, $method);

if (count($reflectionMethod->getParameters()) !== 1) {
throw InvalidArgumentException::create("Converter should have only single parameter: {$reflectionMethod}");
}
}

/**
* @param $object
* @param string $method
* @param Type $sourceType
* @param Type $targetType
* @return ReferenceServiceConverter
* @throws \Ecotone\Messaging\MessagingException
*/
public static function create($object, string $method, Type $sourceType, Type $targetType): self
public function __construct(private object $object, private string $method, private Type $sourceType, private Type $targetType)
{
return new self($object, $method, $sourceType, $targetType);
}

/**
* @inheritDoc
*/
public function convert($source, Type $sourceType, MediaType $sourceMediaType, Type $targetType, MediaType $targetMediaType)
{
return call_user_func([$this->object, $this->method], $source);
return $this->object->{$this->method}($source);
}

/**
Expand Down

This file was deleted.

36 changes: 36 additions & 0 deletions packages/Ecotone/src/Messaging/Conversion/StaticCallConverter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace Ecotone\Messaging\Conversion;

use Ecotone\Messaging\Handler\Type;

/**
* licence Apache-2.0
*/
class StaticCallConverter implements Converter
{
public function __construct(private string $classname, private string $method, private Type $sourceType, private Type $targetType)
{
}

/**
* @inheritDoc
*/
public function convert($source, Type $sourceType, MediaType $sourceMediaType, Type $targetType, MediaType $targetMediaType)
{
return $this->classname::{$this->method}($source);
}

/**
* @inheritDoc
*/
public function matches(Type $sourceType, MediaType $sourceMediaType, Type $targetType, MediaType $targetMediaType): bool
{
return $sourceMediaType->isCompatibleWithParsed(MediaType::APPLICATION_X_PHP)
&& $targetMediaType->isCompatibleWithParsed(MediaType::APPLICATION_X_PHP)
&& $sourceType->isCompatibleWith($this->sourceType)
&& $targetType->acceptType($this->targetType);
}
}
2 changes: 1 addition & 1 deletion packages/Ecotone/src/Messaging/Handler/InterfaceToCall.php
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ public function getMethodAnnotationsOf(ObjectType|string $className): array
return $methodAnnotations;
}

public function isStaticallyCalled(): ?bool
public function isStaticallyCalled(): bool
{
return $this->isStaticallyCalled;
}
Expand Down
Loading
Loading