Ecotone
SponsorBlogGithubSupport and ContactCommunity Channel
  • About
  • Installation
  • How to use
    • CQRS PHP
    • Event Handling PHP
    • Aggregates & Sagas
    • Scheduling in PHP
    • Asynchronous PHP
    • Event Sourcing PHP
    • Microservices PHP
    • Resiliency and Error Handling
    • Laravel Demos
    • Symfony Demos
      • Doctrine ORM
  • Tutorial
    • Before we start tutorial
    • Lesson 1: Messaging Concepts
    • Lesson 2: Tactical DDD
    • Lesson 3: Converters
    • Lesson 4: Metadata and Method Invocation
    • Lesson 5: Interceptors
    • Lesson 6: Asynchronous Handling
  • Enterprise
  • Modelling
    • Introduction
    • Message Bus and CQRS
      • CQRS Introduction - Commands
        • Query Handling
        • Event Handling
      • Aggregate Introduction
        • Aggregate Command Handlers
        • Aggregate Query Handlers
        • Aggregate Event Handlers
        • Advanced Aggregate creation
      • Repositories Introduction
      • Business Interface
        • Introduction
        • Business Repository
        • Database Business Interface
          • Converting Parameters
          • Converting Results
      • Saga Introduction
      • Identifier Mapping
    • Extending Messaging (Middlewares)
      • Message Headers
      • Interceptors (Middlewares)
        • Additional Scenarios
      • Intercepting Asynchronous Endpoints
      • Extending Message Buses (Gateways)
    • Event Sourcing
      • Installation
      • Event Sourcing Introduction
        • Working with Event Streams
        • Event Sourcing Aggregates
          • Working with Aggregates
          • Applying Events
          • Different ways to Record Events
        • Working with Metadata
        • Event versioning
        • Event Stream Persistence
          • Event Sourcing Repository
          • Making Stream immune to changes
          • Snapshoting
          • Persistence Strategies
          • Event Serialization and PII Data (GDPR)
      • Projection Introduction
        • Configuration
        • Choosing Event Streams for Projection
        • Executing and Managing
          • Running Projections
          • Projection CLI Actions
          • Access Event Store
        • Projections with State
        • Emitting events
    • Recovering, Tracing and Monitoring
      • Resiliency
        • Retries
        • Error Channel and Dead Letter
          • Dbal Dead Letter
        • Idempotent Consumer (Deduplication)
        • Resilient Sending
        • Outbox Pattern
        • Concurrency Handling
      • Message Handling Isolation
      • Ecotone Pulse (Service Dashboard)
    • Asynchronous Handling and Scheduling
      • Asynchronous Message Handlers
      • Asynchronous Message Bus (Gateways)
      • Delaying Messages
      • Time to Live
      • Message Priority
      • Scheduling
      • Dynamic Message Channels
    • Distributed Bus and Microservices
      • Distributed Bus
        • Distributed Bus with Service Map
          • Configuration
          • Custom Features
          • Non-Ecotone Application integration
          • Testing
        • AMQP Distributed Bus (RabbitMQ)
          • Configuration
        • Distributed Bus Interface
      • Message Consumer
      • Message Publisher
    • Business Workflows
      • The Basics - Stateless Workflows
      • Stateful Workflows - Saga
      • Handling Failures
    • Testing Support
      • Testing Messaging
      • Testing Aggregates and Sagas with Message Flows
      • Testing Event Sourcing Applications
      • Testing Asynchronous Messaging
  • Messaging and Ecotone In Depth
    • Overview
    • Multi-Tenancy Support
      • Getting Started
        • Any Framework Configuration
        • Symfony and Doctrine ORM
        • Laravel
      • Different Scenarios
        • Hooking into Tenant Switch
        • Shared and Multi Database Tenants
        • Accessing Current Tenant in Message Handler
        • Events and Tenant Propagation
        • Multi-Tenant aware Dead Letter
      • Advanced Queuing Strategies
    • Document Store
    • Console Commands
    • Messaging concepts
      • Message
      • Message Channel
      • Message Endpoints/Handlers
        • Internal Message Handler
        • Message Router
        • Splitter
      • Consumer
      • Messaging Gateway
      • Inbound/Outbound Channel Adapter
    • Method Invocation And Conversion
      • Method Invocation
      • Conversion
        • Payload Conversion
        • Headers Conversion
    • Service (Application) Configuration
    • Contributing to Ecotone
      • How Ecotone works under the hood
      • Ecotone Phases
      • Registering new Module Package
      • Demo Integration with SQS
        • Preparation
        • Inbound and Outbound Adapters and Message Channel
        • Message Consumer and Publisher
  • Modules
    • Overview
    • Symfony
      • Symfony Configuration
      • Symfony Database Connection (DBAL Module)
      • Doctrine ORM
      • Symfony Messenger Transport
    • Laravel
      • Laravel Configuration
      • Database Connection (DBAL Module)
      • Eloquent
      • Laravel Queues
      • Laravel Octane
    • Ecotone Lite
      • Logging
      • Database Connection (DBAL Module)
    • JMS Converter
    • OpenTelemetry (Tracing and Metrics)
      • Configuration
    • RabbitMQ Support
    • Kafka Support
      • Configuration
      • Message partitioning
      • Usage
    • DBAL Support
    • Amazon SQS Support
    • Redis Support
  • Other
    • Contact, Workshops and Support
Powered by GitBook
On this page
  • Available Media Type Converters
  • Media Type Converter
  • Conversion on fly using Routed Messages
  • How to build your own Media Type Converter
  • PHP to PHP Conversions
  • Conversion Array of objects
  • Serializer

Was this helpful?

Export as PDF
  1. Messaging and Ecotone In Depth
  2. Method Invocation And Conversion

Conversion

Conversion PHP

PreviousMethod InvocationNextPayload Conversion

Last updated 1 year ago

Was this helpful?

Command, queries and events are not always objects. When they travel via different channels, coming from outside, they are mostly converted to simplified format, like JSON or XML. At the level of application however we want to deal with it in PHP format, as objects or arrays , so we can understand what are we dealing with.

Moving from one format to another requires conversion. Ecotone does it automatically using Converters. Media Type Converters are responsible for converting data into expected format. It can be for example from JSON to PHP, but it also can be other way around from PHP to JSON.

Available Media Type Converters

Ecotone comes with configured Media Type Converters, if you don't want to build your own.

Media Type Converter

We need to define class for it which implements Converter and is marked by annotation #[MediaTypeConverter].

#[MediaTypeConverter] 
class CustomConverter implements Converter
{
    public function matches(TypeDescriptor $sourceType, MediaType $sourceMediaType, TypeDescriptor $targetType, MediaType $targetMediaType): bool
    {

    }

    public function convert($source, TypeDescriptor $sourceType, MediaType $sourceMediaType, TypeDescriptor $targetType, MediaType $targetMediaType)
    {

    }
}

There are two methods matches and convert. Matches tells Ecotone, if specific Converter can do conversion, by returning true/false. Convert does actual conversion from one type to another.

  1. TypeDescriptor - Describes expected type in PHP format. This can be class, scalar type, array etc.

  2. MediaType - Describes expected Media Type format. This can be application/json, application/xml or application/x-php etc.

  3. $source - is the actual data to be converted.

Conversion on fly using Routed Messages

Suppose we have Command Handler endpoint, which expects PlaceOrderCommand class.

#[CommandHandler("order.place")]
public function placeOrder(PlaceOrderCommand $command)
{
   // do something
}

In our HTTP Controller, we receive JSON and we want to send it to Command Bus:

$this->commandBus->sendWithRouting(
   "order.place", 
   '{"productIds": [1,2]}',
   "application/json"
)

Converter that matches JSON to PHP conversion will be used to do the conversion:

 public function convert($source, TypeDescriptor $sourceType, MediaType $sourceMediaType, TypeDescriptor $targetType, MediaType $targetMediaType)
 {
    // $source - {"productIds": [1,2]}
    // $sourceType - string
    // $sourceMediaType - application/json
    // $targetType - PlaceOrderCommand
    // $targetMediaType - application/x-php
 }

How to build your own Media Type Converter

If we would like to implement JSON to PHP converter, we could start like this:

public function matches(TypeDescriptor $sourceType, MediaType $sourceMediaType, TypeDescriptor $targetType, MediaType $targetMediaType): bool
{
    return $sourceMediaType->isCompatibleWith(MediaType::createApplicationJson()) // if source media type is JSON
        && $targetMediaType->isCompatibleWith(MediaType::createApplicationXPHPObject())    ; // and target media type is PHP
}

This will tell Ecotone that in case source media type is JSON and target media type is PHP, then it should use this converter. Then you could inject into the class specific converter of your use for example Symfony Serializer and make use of it in convert method.

public function convert($source, TypeDescriptor $sourceType, MediaType $sourceMediaType, TypeDescriptor $targetType, MediaType $targetMediaType)
{
    return $this->serializer->deserialize($source, $targetType->toString(), "json");
}

PHP to PHP Conversions

Ecotone does come with simplication for PHP level conversion. Suppose we want to send Query with scalar string type: "61cfc7ea-928f-420f-a8e1-656ae2968254" and convert it to Uuid on receiving side.

$this->queryBus->sendWithRouting(
   "order.getDetails", 
   "61cfc7ea-928f-420f-a8e1-656ae2968254",
   MediaType::APPLICATION_X_PHP
)
#[QueryHandler("order.getDetails")]
public function getOrderDetails(Uuid $orderId)
{
   // do something
}

As you can see query neither, command needs to be class. It can be simple array or even a scalar, it's really up to the developer, what does fit best for him in given scenario.

Let's add PHP Conversion:

class ExampleConverterService
{
    #[Converter] 
    public function convert(string $data) : Uuid
    {
        return Uuid::fromString($data);
    }
}

Ecotonewill read parameter type of Converter, which is string and return type which is Uuid and such Converter will be registered. Conversion does work with more complicated objects, expecting more than one parameter. In that case array can be used in order to construct the object.

class ExampleConverterService
{
    #[Converter] 
    public function convert(array $data) : Coordinates
    {
        return Coordinates::create($data["latitude"], $data["longitude"]);
    }
}

Conversion Array of objects

Suppose we expect array of UUID's.

$this->queryBus->sendWithRouting(
   "order.getDetails", 
   ["61cfc7ea-928f-420f-a8e1-656ae2968254", "d32ee0cc-fd01-474d-b69f-2d2489433f3d"],
   MediaType::APPLICATION_X_PHP
)
/**
*  @param Uuid[] $orderIds
*/
#[QueryHandler("order.getDetails")]
public function getOrders(array $orderIds)
{
   // do something
}

In order to handle such conversion, we do not need to do anything more. We have converter for string to UUID then it will be automatically used in order to handle array of string for UUID conversion. Ecotone does know that parameter $orderIdsis array of UUIDs based on docblock parameter@param Uuid[] $orderIds.

Serializer

Serializer Gateway is built from simple interface

namespace Ecotone\Messaging\Gateway\Converter;

interface Serializer
{
    public function convertFromPHP($data, string $targetMediaType);

    public function convertToPHP($data, string $sourceMediaType, string $targetType);
}

convertFromPHP - This method is responsible for converting source PHP $data to specific target Media Type.

$this->serializer->convertFromPHP([1,2,3], "application/json")

convertToPHP - This method is responsible for converting source with specific media type to target PHP type.

$this->serializer->convertToPHP('{"productId": 1}', "application/json", OrderProduct:class)

As SerializerGateway will be automatically registered in your Dependency Container.

Ecotonedoes delay the conversion to the time, when it's actually needed. In that case it will be just before placeOrder method will be called. Then Payload of , which will be {"productIds": [1,2]} with content Type application/json will be converted to PlaceOrderCommand and content Type application/x-php (default for PHP types).

You may want to serialize/deserialize on the level of your application code using Converters you have already registered. In order to do that Ecotone comes with Serializer

Media Type
JMS Converter
Message
Gateway