diff --git a/migrations/Version20260709122602.php b/migrations/Version20260709122602.php new file mode 100644 index 0000000..d260368 --- /dev/null +++ b/migrations/Version20260709122602.php @@ -0,0 +1,30 @@ +addSql('DROP INDEX IDX_AF382D4E3D4E91C8BF396750 ON checkout'); + $this->addSql('ALTER TABLE checkout CHANGE gateway_name gateway_id VARCHAR(255) NOT NULL'); + $this->addSql('CREATE INDEX IDX_AF382D4EBF396750 ON checkout (id)'); + } + + public function down(Schema $schema): void + { + $this->addSql('DROP INDEX IDX_AF382D4EBF396750 ON checkout'); + $this->addSql('ALTER TABLE checkout CHANGE gateway_id gateway_name VARCHAR(255) NOT NULL'); + $this->addSql('CREATE INDEX IDX_AF382D4E3D4E91C8BF396750 ON checkout (gateway_name, id)'); + } +} diff --git a/src/ApiResource/Gateway/CheckoutApiResource.php b/src/ApiResource/Gateway/CheckoutApiResource.php index 05720d0..17975a0 100644 --- a/src/ApiResource/Gateway/CheckoutApiResource.php +++ b/src/ApiResource/Gateway/CheckoutApiResource.php @@ -12,7 +12,7 @@ use App\Gateway\CheckoutStatus; use App\Gateway\GatewayLink; use App\Gateway\RefundStrategy; use App\Gateway\Tracking; -use App\Mapping\Transformer\GatewayNameMapTransformer; +use App\Mapping\Transformer\GatewayIdMapTransformer; use App\State\ApiResourceStateProvider; use App\State\Gateway\CheckoutStateProcessor; use AutoMapper\Attribute\MapFrom; @@ -47,8 +47,8 @@ class CheckoutApiResource * The desired Gateway to checkout with. */ #[Assert\NotBlank()] - #[MapFrom(property: 'gatewayName', transformer: GatewayNameMapTransformer::class)] - #[MapTo(property: 'gatewayName', transformer: 'source.gateway.name')] + #[MapFrom(property: 'gatewayId', transformer: GatewayIdMapTransformer::class)] + #[MapTo(property: 'gatewayId', transformer: 'source.gateway.id')] public GatewayApiResource $gateway; /** diff --git a/src/ApiResource/Gateway/GatewayApiResource.php b/src/ApiResource/Gateway/GatewayApiResource.php index e94cd81..7fc7f5f 100644 --- a/src/ApiResource/Gateway/GatewayApiResource.php +++ b/src/ApiResource/Gateway/GatewayApiResource.php @@ -21,9 +21,16 @@ use App\State\Gateway\GatewayStateProvider; class GatewayApiResource { #[API\ApiProperty(identifier: true)] + public string $id; + + /** + * The publicly known name of this payment method. + */ public string $name; /** + * The types of GatewayCheckout this Gateway can process. + * * @var array */ public array $supports; diff --git a/src/Benzina/InvestsPump.php b/src/Benzina/InvestsPump.php index a730e85..f3e01fd 100644 --- a/src/Benzina/InvestsPump.php +++ b/src/Benzina/InvestsPump.php @@ -117,7 +117,7 @@ class InvestsPump implements PumpInterface $checkout->setOrigin($user->getAccounting()); $checkout->setStatus($this->getCheckoutStatus($record)); - $checkout->setGatewayName($this->getCheckoutGateway($record)); + $checkout->setGatewayId($this->getCheckoutGatewayId($record)); $checkout->setReturnUrl(self::PLATFORM_RETURN_URL); foreach ($this->getCheckoutTrackings($record) as $tracking) { @@ -396,21 +396,21 @@ class InvestsPump implements PumpInterface } } - private function getCheckoutGateway(array $record): string + private function getCheckoutGatewayId(array $record): string { switch ($record['method']) { case 'tpv': - return CecaGateway::getName(); + return CecaGateway::getId(); case 'paypal': - return PaypalGateway::getName(); + return PaypalGateway::getId(); case 'pool': - return WalletGateway::getName(); + return WalletGateway::getId(); case 'cash': - return CashGateway::getName(); + return CashGateway::getId(); case 'drop': - return DropGateway::getName(); + return DropGateway::getId(); case 'stripe_subscription': - return StripeGateway::getName(); + return StripeGateway::getId(); default: return ''; } diff --git a/src/Dto/Gateway/CheckoutCreationDto.php b/src/Dto/Gateway/CheckoutCreationDto.php index 6bbcd1a..b13a963 100644 --- a/src/Dto/Gateway/CheckoutCreationDto.php +++ b/src/Dto/Gateway/CheckoutCreationDto.php @@ -7,7 +7,7 @@ use App\ApiResource\Accounting\AccountingApiResource; use App\ApiResource\Gateway\GatewayApiResource; use App\Entity\Gateway\Checkout; use App\Gateway\RefundStrategy; -use App\Mapping\Transformer\GatewayNameMapTransformer; +use App\Mapping\Transformer\GatewayIdMapTransformer; use AutoMapper\Attribute\MapFrom; use AutoMapper\Attribute\MapTo; use Symfony\Component\Validator\Constraints as Assert; @@ -18,8 +18,8 @@ class CheckoutCreationDto * The desired Gateway to checkout with. */ #[Assert\NotBlank()] - #[MapFrom(property: 'gatewayName', transformer: GatewayNameMapTransformer::class)] - #[MapTo(property: 'gatewayName', transformer: 'source.gateway.name')] + #[MapFrom(property: 'gatewayId', transformer: GatewayIdMapTransformer::class)] + #[MapTo(property: 'gatewayId', transformer: 'source.gateway.id')] public GatewayApiResource $gateway; /** diff --git a/src/Entity/Gateway/Checkout.php b/src/Entity/Gateway/Checkout.php index 7f059ab..c3d7813 100644 --- a/src/Entity/Gateway/Checkout.php +++ b/src/Entity/Gateway/Checkout.php @@ -29,7 +29,7 @@ use Symfony\Component\Validator\Constraints as Assert; #[MapProvider(EntityMapProvider::class)] #[Gedmo\Loggable()] #[ORM\Index(fields: ['migratedId'])] -#[ORM\Index(fields: ['gatewayName', 'id'])] +#[ORM\Index(fields: ['gateway', 'id'])] #[ORM\Entity(repositoryClass: CheckoutRepository::class)] class Checkout { @@ -43,11 +43,11 @@ class Checkout private ?int $id = null; /** - * The name of the Gateway implementation to checkout with. + * The ID of the Gateway implementation to checkout with. */ #[Assert\NotBlank()] #[ORM\Column(length: 255)] - private ?string $gatewayName = null; + private ?string $gatewayId = null; /** * The Accounting that will issue the Transactions of the GatewayCharges after a successful checkout. @@ -114,14 +114,14 @@ class Checkout return $this->id; } - public function getGatewayName(): ?string + public function getGatewayId(): ?string { - return $this->gatewayName; + return $this->gatewayId; } - public function setGatewayName(string $gatewayName): static + public function setGatewayId(string $id): static { - $this->gatewayName = $gatewayName; + $this->gatewayId = $id; return $this; } diff --git a/src/Filter/GatewayFilter.php b/src/Filter/GatewayFilter.php index b3861cc..038c86b 100644 --- a/src/Filter/GatewayFilter.php +++ b/src/Filter/GatewayFilter.php @@ -50,29 +50,29 @@ final class GatewayFilter extends AbstractFilter [$alias] = $this->addJoinsForNestedProperty($property, $rootAlias, $queryBuilder, $queryNameGenerator, $resourceClass, Join::LEFT_JOIN); } - $aliasedField = \sprintf('%s.gatewayName', $alias); + $aliasedField = \sprintf('%s.gatewayId', $alias); if (\count($values) > 1) { $queryBuilder ->andWhere($queryBuilder->expr()->in($aliasedField, $parameterName)) - ->setParameter($parameterName, array_map(fn($v) => $this->getGatewayName($v), $values)); + ->setParameter($parameterName, array_map(fn($v) => $this->getGatewayId($v), $values)); return; } $queryBuilder ->andWhere($queryBuilder->expr()->eq($aliasedField, $parameterName)) - ->setParameter($parameterName, $this->getGatewayName($values[0])); + ->setParameter($parameterName, $this->getGatewayId($values[0])); } - private function getGatewayName(mixed $value): string + private function getGatewayId(mixed $value): string { $value = \array_slice(\explode('/', $value), -1)[0]; try { $gateway = $this->gatewayLocator->get($value); - return $gateway::getName(); + return $gateway::getId(); } catch (MissingGatewayException $e) { throw new NotFoundHttpException($e->getMessage()); } diff --git a/src/Gateway/Gateway/CashGateway.php b/src/Gateway/Gateway/CashGateway.php index 44cb20c..3dadcae 100644 --- a/src/Gateway/Gateway/CashGateway.php +++ b/src/Gateway/Gateway/CashGateway.php @@ -11,11 +11,16 @@ use Symfony\Component\HttpFoundation\Response; class CashGateway implements GatewayInterface { - public static function getName(): string + public static function getId(): string { return 'cash'; } + public static function getName(): string + { + return 'Cash'; + } + public static function getSupportedChargeTypes(): array { return []; diff --git a/src/Gateway/Gateway/CecaGateway.php b/src/Gateway/Gateway/CecaGateway.php index 345782d..cafaced 100644 --- a/src/Gateway/Gateway/CecaGateway.php +++ b/src/Gateway/Gateway/CecaGateway.php @@ -14,11 +14,16 @@ class CecaGateway implements GatewayInterface { public const LEGACY_MESSAGE = 'This Gateway implementation is only meant to give support to legacy-records. DO NOT USE. DO NOT IMPLEMENT.'; - public static function getName(): string + public static function getId(): string { return 'tpv'; } + public static function getName(): string + { + return 'Credit Card'; + } + public static function getSupportedChargeTypes(): array { return [ diff --git a/src/Gateway/GatewayInterface.php b/src/Gateway/GatewayInterface.php index 79fd864..b0b7113 100644 --- a/src/Gateway/GatewayInterface.php +++ b/src/Gateway/GatewayInterface.php @@ -27,6 +27,11 @@ interface GatewayInterface /** * @return string A short, unique, descriptive string for this Gateway */ + public static function getId(): string; + + /** + * @return string the commercially-preferred displayable name of the Gateway platform + */ public static function getName(): string; /** diff --git a/src/Gateway/GatewayLocator.php b/src/Gateway/GatewayLocator.php index 6720961..be43cec 100644 --- a/src/Gateway/GatewayLocator.php +++ b/src/Gateway/GatewayLocator.php @@ -9,7 +9,7 @@ use App\Gateway\Exception\MissingGatewayException; class GatewayLocator { /** @var GatewayInterface[] */ - private array $gatewaysByName = []; + private array $gatewaysById = []; /** @var GatewayInterface[] */ private array $gatewaysByClass = []; @@ -20,10 +20,10 @@ class GatewayLocator $this->gatewaysByClass[$gateway::class] = $gateway; } - self::validateGatewayNames($this->gatewaysByClass); + self::validateGatewayIDs($this->gatewaysByClass); foreach ($this->gatewaysByClass as $class => $gateway) { - $this->gatewaysByName[$gateway::getName()] = $gateway; + $this->gatewaysById[$gateway::getId()] = $gateway; } } @@ -32,21 +32,21 @@ class GatewayLocator */ public function getAll(): array { - return $this->gatewaysByName; + return $this->gatewaysById; } /** - * @param string $name Name of the Gateway interface implementation + * @param string $id ID of the Gateway interface implementation * - * @throws \Exception When the `$name` does not match to that of an implemented Gateway + * @throws \Exception When the `$id` does not match to that of an implemented Gateway */ - public function get(string $name): GatewayInterface + public function get(string $id): GatewayInterface { - if (!\array_key_exists($name, $this->gatewaysByName)) { - throw new MissingGatewayException($name); + if (!\array_key_exists($id, $this->gatewaysById)) { + throw new MissingGatewayException($id); } - return $this->gatewaysByName[$name]; + return $this->gatewaysById[$id]; } /** @@ -54,31 +54,31 @@ class GatewayLocator */ public function getForCheckout(Checkout $checkout): GatewayInterface { - return $this->get($checkout->getGatewayName()); + return $this->get($checkout->getGatewayId()); } /** - * Ensures the gateway names are unique for each gateway. + * Ensures the gateway IDs are unique for each gateway. * * @param array $gatewayClasses Fully-qualified Gateway class names * * @throws \Exception If there are two different Gateway classes that return the same name string */ - private static function validateGatewayNames(array $gatewayClasses): void + private static function validateGatewayIDs(array $gatewayClasses): void { $gatewaysValidated = []; foreach ($gatewayClasses as $gatewayClass) { - $gatewayName = $gatewayClass::getName(); + $gatewayId = $gatewayClass::getId(); - if (\array_key_exists($gatewayName, $gatewaysValidated)) { + if (\array_key_exists($gatewayId, $gatewaysValidated)) { throw new DuplicateGatewayException( - $gatewayName, + $gatewayId, $gatewayClass::class, - $gatewaysValidated[$gatewayName]::class + $gatewaysValidated[$gatewayId]::class ); } - $gatewaysValidated[$gatewayName] = $gatewayClass; + $gatewaysValidated[$gatewayId] = $gatewayClass; } } } diff --git a/src/Gateway/Paypal/PaypalGateway.php b/src/Gateway/Paypal/PaypalGateway.php index 7379649..ff6753e 100644 --- a/src/Gateway/Paypal/PaypalGateway.php +++ b/src/Gateway/Paypal/PaypalGateway.php @@ -44,11 +44,16 @@ class PaypalGateway extends AbstractGateway private PaypalService $paypal, ) {} - public static function getName(): string + public static function getId(): string { return 'paypal'; } + public static function getName(): string + { + return 'PayPal'; + } + public static function getSupportedChargeTypes(): array { return [ diff --git a/src/Gateway/Stripe/StripeGateway.php b/src/Gateway/Stripe/StripeGateway.php index ca76449..c1887dd 100644 --- a/src/Gateway/Stripe/StripeGateway.php +++ b/src/Gateway/Stripe/StripeGateway.php @@ -37,11 +37,16 @@ class StripeGateway extends AbstractGateway $this->stripe = new StripeClient($stripeApiKey); } - public static function getName(): string + public static function getId(): string { return 'stripe'; } + public static function getName(): string + { + return 'Stripe'; + } + public static function getSupportedChargeTypes(): array { return [ diff --git a/src/Gateway/Wallet/WalletGateway.php b/src/Gateway/Wallet/WalletGateway.php index 21a1356..188b46f 100644 --- a/src/Gateway/Wallet/WalletGateway.php +++ b/src/Gateway/Wallet/WalletGateway.php @@ -18,11 +18,16 @@ use Symfony\Component\HttpFoundation\Response; class WalletGateway implements GatewayInterface { - public static function getName(): string + public static function getId(): string { return 'wallet'; } + public static function getName(): string + { + return 'Wallet'; + } + public static function getSupportedChargeTypes(): array { return [ diff --git a/src/Mapping/Transformer/GatewayNameMapTransformer.php b/src/Mapping/Transformer/GatewayIdMapTransformer.php similarity index 84% rename from src/Mapping/Transformer/GatewayNameMapTransformer.php rename to src/Mapping/Transformer/GatewayIdMapTransformer.php index 8f5b132..95f99f4 100644 --- a/src/Mapping/Transformer/GatewayNameMapTransformer.php +++ b/src/Mapping/Transformer/GatewayIdMapTransformer.php @@ -6,7 +6,7 @@ use App\ApiResource\Gateway\GatewayApiResource; use App\Gateway\GatewayLocator; use AutoMapper\Transformer\PropertyTransformer\PropertyTransformerInterface; -class GatewayNameMapTransformer implements PropertyTransformerInterface +class GatewayIdMapTransformer implements PropertyTransformerInterface { public function __construct( private GatewayLocator $gatewayLocator, @@ -17,6 +17,7 @@ class GatewayNameMapTransformer implements PropertyTransformerInterface $gateway = $this->gatewayLocator->get($value); $resource = new GatewayApiResource(); + $resource->id = $gateway::getId(); $resource->name = $gateway::getName(); $resource->supports = $gateway::getSupportedChargeTypes(); diff --git a/src/Service/Gateway/CheckoutService.php b/src/Service/Gateway/CheckoutService.php index 5148798..e96a6c0 100644 --- a/src/Service/Gateway/CheckoutService.php +++ b/src/Service/Gateway/CheckoutService.php @@ -34,7 +34,7 @@ class CheckoutService GatewaysController::REDIRECT, [ 'type' => $type, - 'gateway' => $checkout->getGatewayName(), + 'gateway' => $checkout->getGatewayId(), 'checkoutId' => $checkout->getId(), ...$parameters, ], diff --git a/src/State/Gateway/GatewayStateProvider.php b/src/State/Gateway/GatewayStateProvider.php index 8ef5f31..95fb621 100644 --- a/src/State/Gateway/GatewayStateProvider.php +++ b/src/State/Gateway/GatewayStateProvider.php @@ -24,7 +24,7 @@ class GatewayStateProvider implements ProviderInterface case API\GetCollection::class: return $this->getGateways(); case API\Get::class: - return $this->getGateway($uriVariables['name']); + return $this->getGateway($uriVariables['id']); default: return $this->getGateways(); } @@ -48,10 +48,10 @@ class GatewayStateProvider implements ProviderInterface return $gateways; } - private function getGateway(string $name): GatewayApiResource + private function getGateway(string $id): GatewayApiResource { try { - $gateway = $this->gateways->get($name); + $gateway = $this->gateways->get($id); foreach ($gateway::getAllowedRoles() as $role) { $isGranted = $this->security->isGranted($role, $this->security->getUser()); @@ -70,6 +70,7 @@ class GatewayStateProvider implements ProviderInterface private function toResource(GatewayInterface $gateway): GatewayApiResource { $resource = new GatewayApiResource(); + $resource->id = $gateway::getId(); $resource->name = $gateway::getName(); $resource->supports = $gateway::getSupportedChargeTypes();