0

TLDR: How combine rich domain model with "heavy" setters with simple HTML form mapping?

Problem occurs when setter of one property change other properties (directly or by using setters - this doesn't matter).

Sample class for better explaining (in PHP, but this doesn't matter - I think):

class Product {

private $name;
private $cost;
private $profit;
private $price;

public function getName() {
    return $this->name;
}

public function getCost() {
    return $this->cost;
}

public function getProfit() {
    return $this->profit;
}

public function getPrice() {
    return $this->price;
}

public function setName($name) {
    $this->name = $name;
    return $this;
}

public function setCost($cost) {
    if ($this->cost !== $cost) {
        $this->cost = $cost;
        $this->setPrice($this->getCost() + $this->getProfit());
    }
    return $this;
}

public function setProfit($profit) {
    if ($this->profit !== $profit) {
        $this->profit = $profit;
        $this->setPrice($this->getCost() + $this->getProfit());
    }
    return $this;
}

public function setPrice($price) {
    if ($this->price !== $price) {
        $this->price = $price;
        $this->setProfit($this->getPrice() - $this->getCost());
    }
    return $this;
}

}

The idea is this sample is that: you can set cost (of buying/creating product) and profit you want to earn - then the price (for selling product) get calculated. Also, you can set change the price - then profit is calculated. (Changing cost could trigger to change profit not price, but it doesn't matter for the problem).

For example:

$foo = new Product();
$foo->setName("Foo");
$foo->setCost(100);
$foo->setPrice(110);
assert($foo->getProfit() == 10);
$foo->setProfit(30);
assert($foo->getPrice() == 130);

I need to have rich object in "backend" code due to many reasons (ie. command line frontend and CRON jobs).

In HTML frontend you get form with 3 inputs corresponding to cost, profit and price. When user changes values and submit form order of setters does matters and can mess things up. For example:

  • user goes click to edit product button
  • sees form with values: cost=100, profit=10, price=110
  • changes profit to 20
  • submit form

And the problem is: Backend mapper gets values from POST form and calls: setCost(100), setProfit(20) and then setPrice(110) which is bad because it is old price which should be changed to 120 (user wanted to have 20 profit and 100 cost).

Only solution i see is to implement all domain model logic also in frontend - in JavaScript - so changing cost/profit inputs trigger to change value in price input. Then all inputs have right values and are POSTed data can be put without "overriding" problem. It is easy with this sample but impossible when you have many fields (time consuming and error prone to write same code in two different languages) or really complex logic between them (not everything can be easy implemented in JS).

Any ideas how to solve this? :)

PS: Using transient properties and lazy evaluation (ie. only cost and price is property and editable, and profit is always calculated) is not an option. I must be able to change from both ways. Also it is in inconvenient for some heavy calculations - all props must be present and then saved to database.

Stawi
  • 1

1 Answers1

0

If you deal with legacy code one option would be to send a request to backend on field change and to retrieve an updated fields in response, so basicaly on frontend you have to imlement only form update. But this is not a nice solution, I would rather concentrate on what app realy needs to provide as a value for the user. If you let user chane all 3 fields why should you be paranoid. he knows what he is doing right? Or if you have validation rules then evaluate on submit. You probably already see how requirements can change your behaviour.

Vlad Filimon
  • 534
  • 3
  • 5
  • I like idea of sending request to backend on field change. Why you think this is not a nice solution? Only thing that might cause trouble is speed/latency. App have a lot of conjugation between fields and it must be seen on GUI and must be editable from all sides. – Stawi Oct 04 '16 at 09:58
  • My opinion is that a program has always an input an output which should be kept obvious as a guaranty for good user experience. In your case fields act as input and output at the same time. But if intended users and purpose of app play well then I think it is totally fine. – Vlad Filimon Oct 04 '16 at 22:15