-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path09_model_lifecycle2.php
More file actions
96 lines (77 loc) · 3.69 KB
/
09_model_lifecycle2.php
File metadata and controls
96 lines (77 loc) · 3.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
<?php
declare(strict_types=1);
/**
* Example 09 — Real-World Pattern: Domain Model with Event-Driven Lifecycle
*
* This example shows the intended usage pattern: a domain model whose
* getters and setters go through event chains, allowing external code to
* hook into every property change and read.
*
* This is the same pattern used in production (e.g. finance library) where
* traits like StatusTrait, CostTrait, NamedTrait wrap every property
* access in EventExecutor::run() + CommonEvents helpers.
*/
require __DIR__ . '/../vendor/autoload.php';
use Minfra\Chains\EventExecutor;
use Minfra\Chains\EventInterface;
use Minfra\Chains\CallbackTrait;
use Minfra\Chains\CommonEvents;
use Minfra\Chains\Result;
use Minfra\Chains\BasicResultInterface;
use Minfra\Chains\Meta;
class Product2 implements \Minfra\Chains\CallbackInterface {
use CallbackTrait;
protected string $price;
protected int $type;
const EVENT_ON_SET_TYPE = "set_type";
const EVENT_ON_GET_TYPE = "get_type";
const EVENT_ON_SET_PRICE = "set_price";
const EVENT_ON_GET_PRICE = "get_price";
function setType(int $type): BasicResultInterface {
return EventExecutor::run($this, static::EVENT_ON_SET_TYPE, ...CommonEvents::setter(['type' => $type]));
}
function getType(): Result {
$type = $this->type ?? null;
return EventExecutor::run($this, static::EVENT_ON_GET_TYPE, ...CommonEvents::getter('type', $type));
}
function setPrice(string $price): BasicResultInterface {
list($meta, $setter_cb) = CommonEvents::setter(['price' => $price]);
return EventExecutor::run($this, static::EVENT_ON_SET_PRICE, $meta, [
EventInterface::ON_BEFORE => [[$this, "_ensure_correct_price"], [$this, "_ensure_correct_decimal_price"]],
EventInterface::ON_MID => [$setter_cb],
EventInterface::ON_OK => fn(Meta $meta) => error_log("price is: {$meta->price}"),
]); // CommonEvents provides wheels for working with properties
}
function getPrice(): Result {
$price = $this->price ?? null;
return EventExecutor::run($this, static::EVENT_ON_GET_PRICE, ...CommonEvents::getter('price', $price));
}
protected function _ensure_correct_price(Meta $meta): BasicResultInterface|true {
if (!is_numeric($meta->price)) {
return Result::false("invalid_price", $meta); // Or simply: Result::false("invalid_price");
}
return true; // when returning true. it automatically passes the $meta to the next phase.
}
protected function _ensure_correct_decimal_price(Meta $meta): BasicResultInterface|true {
// $meta->price = bcmath($meta->price, '1', 2);
return true;
}
}
$product = new Product2();
$product->appendCallback((new \Minfra\Chains\CallbackEntry($product::EVENT_ON_SET_PRICE, \Minfra\Chains\CallbackEntryInterface::EVENT_PRE))->setCallback(function(Meta $meta) {
/** @var Product2 $product */
$product = $meta->this;
if ($product->getType()->data()->type === 222) {
if ($meta->price > "20") {
return Result::false("invalid_product_222_issue", ['reason' => 'cannot be higher than 20']);
// or if you prefer using meta: return Result::false("invalid_product_222_issue", Meta::make(reason: 'cannot be higher than 20'));
}
}
return true;
}));
$product->appendCallback((new \Minfra\Chains\CallbackEntry($product::EVENT_ON_SET_PRICE, \Minfra\Chains\CallbackEntryInterface::EVENT_POST))->setCallback(function(Meta $meta) {
var_dump("I got the price: {$meta->price}. let's do something with it.");
}));
$product->setType(222);
var_dump($product->setPrice('21')->ok()); // false
var_dump($product->setPrice('19')->ok()); // true