How to convert a DTO to Domain Objects - domain-driven-design

I'm trying to apply ubiquitous language to my domain objects.
I want to convert a Data Transfer Object coming from a client into the domain object. The Aggregate's Constructor only accepts the required fields, and the rest of parameters should be passed using aggregate's API even when the Aggregate is being created(by say CreateAggregate command).
But the DTO to Aggregate mapping code becomes a bit messy:
if(DTO.RegistrantType == 0){
registrantType = RegistrantType.Person()
}
elseif(DTO.RegistrantType == 1){
registrantType = RegistrantType.Company()
}
//.....
//.....
var aggregate = new Aggregate(
title,
weight,
registrantType,
route,
callNumber,
)
//look at this one:
if(DTO.connectionType == 0){
aggregate.Route(ConnectionType.InCity(cityId))
}
elseif(DTO.connectionType == 1){
aggregate.Route(ConnectionType.Intercity(DTO.originCityId,DTO.DestinationCityId)
}
//..........
//..........
One thing I should mention is that this problem doesn't seem a domain specific problem.
How can I reduce these If-Else statements without letting my domain internals leakage, and with being sure that the aggregate(not a mapping tool) doesn't accept values that can invalide it's business rules, and with having the ubiquitous language applied?
Please don't tell me I can use AoutoMapper to do the trick. Please read the last part carefully.'
Thank you.

A typical answer would be to convert the DTO (which is effectively a message) into a Command, where the command has all of the arguments expressed as domain specific value types.
void doX(DTO dto) {
Command command = toCommand(dto)
doX(command)
}
void doX(Command command) {
// ...
aggregate.Route(command.connectionType)
}
It's fairly common for the toCommand logic use something like a Builder pattern to improve the readability of the code.
if(DTO.connectionType == 0){
aggregate.Route(ConnectionType.InCity(cityId))
}
elseif(DTO.connectionType == 1){
aggregate.Route(ConnectionType.Intercity(DTO.originCityId,DTO.DestinationCityId)
}
In cases like this one, the strategy pattern can help
ConnectionTypeFactory f = getConnectionFactory(DTO.connectionType)
ConnectionType connectionType = f.create(DTO)
Once that you recognize that ConnectionTypeFactory is a thing, you can think about building lookup tables to choose the right one.
Map<ConnectionType, ConnectionTypeFactory> lookup = /* ... */
ConnectionTypeFactory f = lookup(DTO.connectionType);
if (null == f) {
f = defaultConnectionFactory;
}

So why don't you use more inheritance
for example
class CompanyRegistration : Registration {
}
class PersonRegistraiton : Registration {
}
then you can use inheritance instead of your if/else scenario's
public class Aggregate {
public Aggregate (CompanyRegistration) {
registantType = RegistrantType.Company();
}
public Aggregate (PersonRegistration p) {
registrantType = RegistrantType.Person();
}
}
you can apply simmilar logic for say a setRoute method or any other large if/else situations.
Also, i know you don't want to hear it, you can write your own mapper (inside the aggegate) that maps and validates it's business logic
for example this idea comes from fluentmapper
var mapper = new FluentMapper.ThatMaps<Aggregate>().From<DTO>()
.ThatSets(x => x.title).When(x => x != null).From(x => x.title)
It isn't too hard to write your own mapper that allow this kind of rules and validates your properties. And i think it will improve readability

Related

the right way to return a Single from a CompletionStage

I'm playing around with reactive flows using RxJava2, Micronaut and Cassandra. I'm new to rxjava and not sure what is the correct way to return a of List Person in the best async manner?
data is coming from a Cassandra Dao interface
public interface PersonDAO {
#Query("SELECT * FROM cass_drop.person;")
CompletionStage<MappedAsyncPagingIterable<Person>> getAll();
}
that gets injected into a micronaut controller
return Single.just(personDAO.getAll().toCompletableFuture().get().currentPage())
.subscribeOn(Schedulers.io())
.map(people -> HttpResponse.ok(people));
OR
return Single.just(HttpResponse.ok())
.subscribeOn(Schedulers.io())
.map(it -> it.body(personDAO.getAll().toCompletableFuture().get().currentPage()));
OR switch to RxJava3
return Single.fromCompletionStage(personDAO.getAll())
.map(page -> HttpResponse.ok(page.currentPage()))
.onErrorReturn(throwable -> HttpResponse.ok(Collections.emptyList()));
Not a pro of RxJava nor Cassandra :
In your first and second example, you are blocking the thread executing the CompletionStage with get, even if you are doing it in the IO thread, I would not recommand doing so.
You are also using a Single wich can emit, only one value, or an error. Since you want to return a List, I would sugest to go for at least an Observable.
Third point, the result from Cassandra is paginated, I don't know if it's intentionnaly but you list only the first page, and miss the others.
I would try a solution like the one below, I kept using the IO thread (the operation may be costly in IO) and I iterate over the pages Cassandra fetch :
/* the main method of your controller */
#Get()
public Observable<Person> listPersons() {
return next(personDAO.getAll()).subscribeOn(Schedulers.io());
}
private Observable<Person> next(CompletionStage<MappedAsyncPagingIterable<Person>> pageStage) {
return Single.fromFuture(pageStage.toCompletableFuture())
.flatMapObservable(personsPage -> {
var o = Observable.fromIterable(personsPage.currentPage());
if (!personsPage.hasMorePages()) {
return o;
}
return o.concatWith(next(personsPage.fetchNextPage()));
});
}
If you ever plan to use reactor instead of RxJava, then you can give cassandra-java-driver-reactive-mapper a try.
The syntax is fairly simple and works in compile-time only.

DDD - Change entity inside aggregate

After reading DDD - Modifications of child objects within aggregate and Update an entity inside an aggregate I still puzzled with the implementation of entity changes within an aggregate. For what I understand the aggregate root speaks for the whole (or entire aggregate) and delegates 'commands' changes down to the rest.
This last part, the delegating down to the rest is causing some problems. In the example below I want to change the quantity of a particular orderline. I'm addressing the root 'Order' and telling it to change the quantity of a orderline identified by a local identifier.
When all business rules are met an event can be created and applied on the aggregate. For now all the events are applied on the aggregate root, and I think that is a good practices, so all the commands are directed on the root and this changes the state of the aggregate. Also the aggregate root is the only one creating events, letting the world know what happened.
class Order extends AggregateRoot
{
private $orderLines = [];
public function changeOrderLineQuantity(string $id, int $quantity)
{
if ($quantity < 0) {
throw new \Exception("Quantity may not be lower than zero.");
}
$this->applyChange(new OrderLineQuantityChangedEvent(
$id, $quantity
));
}
private function onOrderLineQuantityChangedEvent(OrderLineQuantityChangedEvent $event)
{
$orderLine = $this->orderLines[$event->getId()];
$orderLine->changeQuantity($event->getQuantity());
}
}
class OrderLine extends Entity
{
private $quantity = 0;
public function changeQuantity(int $quantity)
{
if ($quantity < 0) {
throw new \Exception("Quantity may not be lower than zero.");
}
$this->quantity = $quantity;
}
}
But, when I am applying this implementation I have a problem, as you notice the business rule for checking the value of $quantity is located in two classes. This is on purpose, because I don't really know the best spot. The rule is only applied within the OrderLine class, thus it doesn't belong in Order. But when I'm removing this from Order events will be created that cannot be applied, because not all business rules are met. This is also something that is not wanted.
I can created a method in the class OrderLine like:
public function canChangeQuantity(int $quantity)
{
if ($quantity < 0) {
return false;
}
return true;
}
changing the method in the OrderLine to:
public function changeQuantity(int $quantity)
{
if ($this->canChangeQuantity($quantity) < 0) {
throw new \Exception("Quantity may not be lower than zero.");
}
$this->quantity = $quantity;
}
Now I can alter the method within the Order class to:
public function changeOrderLineQuantity(string $id, int $quantity)
{
$orderLine = $this->orderLines[$event->getId()];
if ($orderLine->canChangeQuantity($quantity)) {
throw new \Exception("Quantity may not be lower than zero.");
}
$this->applyChange(new OrderLineQuantityChangedEvent(
$id, $quantity
));
}
Ensuring the business logic is where it belongs and also not in two places. This is an option, but if the complexity increases and the model becomes larger I can imagine that these practices become more complex.
For now I have to questions:
(1) How do you cope with alterations deep within the aggregate that are started from the root?
(2) When the business rules increase (e.g, max quantity is 10, but on Monday 3 more, and for product X max is 3 items). Is it good practices to supply each command / method on the aggregate root a domain services that is validating these business rules?
I have a problem, as you notice the business rule for checking the value of $quantity is located in two classes.
From an "object oriented" perspective, Order::changeOrderLineQuantity($id, $quantity) is a message. It is normal for messages to have schema, and for schema to restrict the range of values that are permitted in any given field.
So this code here:
public function changeOrderLineQuantity(string $id, int $quantity)
{
if ($quantity < 0) {
throw new \Exception("Quantity may not be lower than zero.");
}
is an example of message validation, you are checking to see that quantity is in the allowed range of values because the general-purpose int primitive is too permissive.
What domain modelers using strongly typed languages will often do here is introduce a new type, aka a ValueObject, that models the data with its range restrictions.
// Disclaimer: PHP is not my first language
class Quantity {
public function __construct(int $quantity) {
if ($quantity < 0) {
throw new \Exception("Quantity may not be lower than zero.");
}
$this.quantity = quantity
}
// ...
}
In the ease cases, Quantity, as understood by Orders::changeOrderLineQuantity(...) is the same domain concept as Quantity as understood by OrderLineQuantityChangedEvent(...) is the same domain concept as Quantity as understood by OrderLine::changeQuantity(...), and therefore you can re-use the same type everywhere; the type checker therefore ensures that the correct constraints are satisfied.
Edit
As noted by Eben Roux in the comments to this question, Quantity here should not be understood to be some universal, general-purpose type. It is instead specific to the context of Orders and OrderLines, and other parts of the code that share the same constraints for the same reason.
A complete solution might have several different Quantity types in different namespaces.

Camel-Olingo2: The metadata constraints '[Nullable=true, MaxLength=16]' do not match the literal

I'm using camel-olingo2 component for query SAP SuccessFactors on ODataV2 endpoints. The route is:
from("direct:start")
.to(olingoEndpoint)
.process(paging)
.loopDoWhile(simple("\${header.CamelOlingo2.\$skiptoken} != null"))
.to(olingoEndpoint)
.process(paging)
.end()
Paging processor is:
Processor paging = new Processor() {
#Override
void process(Exchange g) throws Exception {
ODataDeltaFeed feed = g.in.getMandatoryBody(ODataDeltaFeed)
if (consumer) feed.getEntries().forEach(consumer)
String next = feed.getFeedMetadata().getNextLink()
if (next) {
List<NameValuePair> lst = URLEncodedUtils.parse(new URI(next), StandardCharsets.UTF_8)
NameValuePair skiptoken = lst.find { it.name == "\$skiptoken" }
g.out.headers."CamelOlingo2.\$skiptoken" = skiptoken.value
} else {
g.out.headers.remove("CamelOlingo2.\$skiptoken")
}
}
}
Everything is OK with most of entities but there are fields for several entities with wrong nullability or data length so I got:
Caused by: org.apache.olingo.odata2.api.edm.EdmSimpleTypeException: The metadata constraints '[Nullable=true, MaxLength=16]' do not match the literal 'Bor.Kralja Petra I.16'.
at org.apache.olingo.odata2.core.edm.EdmString.internalValueOfString(EdmString.java:62)
at org.apache.olingo.odata2.core.edm.AbstractSimpleType.valueOfString(AbstractSimpleType.java:91)
at org.apache.olingo.odata2.core.ep.consumer.JsonPropertyConsumer.readSimpleProperty(JsonPropertyConsumer.java:236)
at org.apache.olingo.odata2.core.ep.consumer.JsonPropertyConsumer.readPropertyValue(JsonPropertyConsumer.java:169)
In documentation for Olingo2 camel component I cannot find the way to disable this checking or other walkaround. Can you suggest me the good way?
Please do not recommend server-side data changes, ex metadata modifiyng, it's out of scope for this task.
I have plan B: to use HTTPS requests with JSON parsing, it's quite simple but little boring.

Create own action to clone/duplicate TYPO3 8.7 extbase object with nested child elements

I build my extbased TYPO3 extension in TYPO3 8.7 . It is a Backend-Module. In the controller, i write my own action to clone the object.
In this example, i want to clone/duplicate the object 'Campaign' and safe it with a modified title, like add the 'copy' text to the title.
But the new object should have also its own new child elements that must be exact copies.
When the action is called, i get only a copy of the Object, but no childs. Is there an example or best case how to handle this task? I did not find, even i found some questions and answers that are on the same topic, but older version. i hope that upd to date, there is a more straight forward solution. Thank you for every hint that points me to the right ideas and maybe an up to date and version example. Here is what i have i my controller. How do i implement recursiv copying of all child elements (and some childs have childs, too)?
/**
* action clone
* #param \ABC\Copytest\Domain\Model\Campaign $campaign
* #return void
* #var \ABC\Copytest\Domain\Model\Campaign $newCampaign
*/
public function cloneAction(\ABC\Copytest\Domain\Model\Campaign $campaign) {
$newCampaign = $this->objectManager->get("ABC\Copytest\Domain\Model\Campaign");
$properties = $campaign->_getProperties();
unset($properties['uid']);
foreach ($properties as $key => $value) {
$newCampaign->_setProperty($key, $value);
}
$newCampaign->_setProperty('title', $properties['title']. ' COPY');
$this->campaignRepository->add($newCampaign);
$this->addFlashMessage('Clone was created', '', \TYPO3\CMS\Core\Messaging\AbstractMessage::OK);
$this->redirect('list');
}
I am aware that this question has been answered a long time ago. But I want to provide my solution to create a deep copy for further reference. Tested on TYPO3 9.5.8.
private function deepcopy($object)
{
$clone = $this->objectManager->get(get_class($object));
$properties = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getGettableProperties($object);
foreach ($properties as $propertyName => $propertyValue) {
if ($propertyValue instanceof \TYPO3\CMS\Extbase\Persistence\ObjectStorage) {
$v = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\ObjectStorage::class);
foreach($propertyValue as $subObject) {
$subClone = $this->deepcopy($subObject);
$v->attach($subClone);
}
} else {
$v = $propertyValue;
}
if ($v !== null) {
\TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty($clone, $propertyName, $v);
}
}
return $clone;
}
There is one approach which tackles this usecase from a different POV, namely that request argument values without an identity are automatically put into fresh objects which can then be persisted. This basically clones the original objects. This is what you need to do:
Add a view which has fields for all properties of your object, hidden fields are fine too. This can for example be an edit view with a separate submit button to call your clone action.
Add a initializeCloneAction() and get the raw request arguments via $this->request->getArguments().
Now do unset($arguments[<argumentName>]['__identity']);, do the same for every relation your object has if you want copies instead of shared references.
Store the raw request arguments again via $this->request->setArguments($arguments).
Finally allow the creation of new objects in the property mapping configuration of your argument and possibly all relation properties.
This is how a full initializeCloneAction() could look like:
public function initializeCloneAction()
{
$arguments = $this->request->getArguments();
unset(
$arguments['campaign']['__identity'],
$arguments['campaign']['singleRelation']['__identity'],
);
foreach (array_keys($arguments['campaign']['multiRelation']) as $i) {
unset($arguments['campaign']['multiRelation'][$i]['__identity']);
}
$this->request->setArguments($arguments);
// Allow object creation now that we have new objects
$this->arguments->getArgument('campaign')->getPropertyMappingConfiguration()
->setTypeConverterOption(PersistentObjectConverter::class, PersistentObjectConverter::CONFIGURATION_CREATION_ALLOWED, true)
->allowCreationForSubProperty('singleRelation')
->getConfigurationFor('multiRelation')
->allowCreationForSubProperty('*');
}
Now if you submit your form using the clone action, your clone action will get a fully populated but new object which you can store in your repository as usual. Your cloneAction() will then be very simple:
public function cloneAction(Campaign $campaign)
{
$this->campaignRepository->add($campaign);
$this->addFlashMessage('Campaign was copied successfully!');
$this->redirect('list');
}
If you have "LazyLoadingProxy" instance in your object you need add one more conditions.
if ($propertyValue instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy) {
$objectStorage = $propertyValue->_loadRealInstance();
}
This is my solution for "deepcopy" function:
private function deepcopy($object)
{
$clone = $this->objectManager->get(get_class($object));
$properties = \TYPO3\CMS\Extbase\Reflection\ObjectAccess::getGettableProperties($object);
foreach ($properties as $propertyName => $propertyValue) {
if ($propertyValue instanceof \TYPO3\CMS\Extbase\Persistence\ObjectStorage) {
$objectStorage = $this->objectManager->get(\TYPO3\CMS\Extbase\Persistence\ObjectStorage::class);
foreach ($propertyValue as $subObject) {
$subClone = $this->deepcopy($subObject);
$objectStorage->attach($subClone);
}
} elseif ($propertyValue instanceof \TYPO3\CMS\Extbase\Persistence\Generic\LazyLoadingProxy) {
$objectStorage = $propertyValue->_loadRealInstance();
} else {
$objectStorage = $propertyValue;
}
if ($objectStorage !== null) {
\TYPO3\CMS\Extbase\Reflection\ObjectAccess::setProperty($clone, $propertyName, $objectStorage);
}
}
return $clone;
}
I think a good solution is, to emulate the backend-function.
See the code-example (german text)
http://blog.marcdesign.ch/2015/05/27/typo3-extbase-objekte-kopieren/
The general idea is to extend the TYPO3\CMS\Core\DataHandling\DataHandler and use the parent-method copyRecord. You declare your predefined backend-user to $this->BE_USER in your extend class. The obejct of your predefined backenduser can you get by using the class TYPO3\\CMS\\Backend\\FrontendBackendUserAuthentication and the known name of you predefined backenduser. Your user should have admin-rights and you should define the $BE_USER->uc_default['copyLevels']= '9999'; and declare $BE_USER->uc = $BE_USER->uc_default.
I have not checked, if the declaration $GLOBALS['PAGES_TYPES'][254]['allowedTables'] = '*'; is really needed.
The method copyRecorditself needs mainly the table-name, the uid-value, the pid-value and a language-object as parameters.The languages-object can you get $GLOBALS['lang'], which can although be generated by instanciating \TYPO3\CMS\Lang\LanguageService to $GLOBALS['lang'] and \TYPO3\CMS\Core\Charset\CharsetConverter to $GLOBALS['LANG']->csConvObj.
Sorry about my poor english.

IEnumerable<T>.ConvertAll & DDD

I have an interesting need for an extension method on the IEumerable interface - the same thing as List.ConvertAll. This has been covered before here and I found one solution here. What I don't like about that solution is he builds a List to hold the converted objects and then returns it. I suspect LINQ wasn't available when he wrote his article, so my implementation is this:
public static class IEnumerableExtension
{
public static IEnumerable<TOutput> ConvertAll<T, TOutput>(this IEnumerable<T> collection, Func<T, TOutput> converter)
{
if (null == converter)
throw new ArgumentNullException("converter");
return from item in collection
select converter(item);
}
}
What I like better about this is I convert 'on the fly' without having to load the entire list of whatever TOutput's are. Note that I also changed the type of the delegate - from Converter to Func. The compilation is the same but I think it makes my intent clearer - I don't mean for this to be ONLY type conversion.
Which leads me to my question: In my repository layer I have a lot of queries that return lists of ID's - ID's of entities. I used to have several classes that 'converted' these ID's to entities in various ways. With this extension method I am able to boil all that down to code like this:
IEnumerable<Part> GetBlueParts()
{
IEnumerable<int> keys = GetBluePartKeys();
return keys.ConvertAll<Part>(PartRepository.Find);
}
where the 'converter' is really the repository's Find-by-ID method. In my case, the 'converter' is potentially doing quite a bit. Does anyone see any problems with this approach?
The main issue I see with this approach is it's completely unnecessary.
Your ConvertAll method is nothing different than Enumerable.Select<TSource,TResult>(IEnumerable<TSource>, Func<TSource,TResult>), which is a standard LINQ operator. There's no reason to write an extension method for something that already is in the framework.
You can just do:
IEnumerable<Part> GetBlueParts()
{
IEnumerable<int> keys = GetBluePartKeys();
return keys.Select<int,Part>(PartRepository.Find);
}
Note: your method would require <int,Part> as well to compile, unless PartRepository.Find only works on int, and only returns Part instances. If you want to avoid that, you can probably do:
IEnumerable<Part> GetBlueParts()
{
IEnumerable<int> keys = GetBluePartKeys();
return keys.Select(i => PartRepository.Find<Part>(i)); // I'm assuming that fits your "Find" syntax...
}
Why not utilize the yield keyword (and only convert each item as it is needed)?
public static class IEnumerableExtension
{
public static IEnumerable<TOutput> ConvertAll<T, TOutput>
(this IEnumerable<T> collection, Func<T, TOutput> converter)
{
if(null == converter)
throw new ArgumentNullException("converter");
foreach(T item in collection)
yield return converter(item);
}
}

Resources