1: | <?php declare(strict_types=1); |
2: | |
3: | namespace Salient\Sync\Support; |
4: | |
5: | use Salient\Contract\Sync\DeferredEntityInterface; |
6: | use Salient\Contract\Sync\LinkType; |
7: | use Salient\Contract\Sync\SyncContextInterface; |
8: | use Salient\Contract\Sync\SyncEntityInterface; |
9: | use Salient\Contract\Sync\SyncProviderInterface; |
10: | use Salient\Contract\Sync\SyncStoreInterface; |
11: | use Closure; |
12: | use LogicException; |
13: | |
14: | |
15: | |
16: | |
17: | |
18: | |
19: | |
20: | |
21: | |
22: | |
23: | final class DeferredEntity implements DeferredEntityInterface |
24: | { |
25: | private SyncProviderInterface $Provider; |
26: | private ?SyncContextInterface $Context; |
27: | |
28: | private string $Entity; |
29: | |
30: | private $EntityId; |
31: | |
32: | private $Replace = null; |
33: | |
34: | private ?Closure $Callback = null; |
35: | |
36: | private ?SyncEntityInterface $Resolved = null; |
37: | |
38: | |
39: | |
40: | |
41: | |
42: | |
43: | |
44: | |
45: | |
46: | private function __construct( |
47: | SyncProviderInterface $provider, |
48: | ?SyncContextInterface $context, |
49: | string $entity, |
50: | $entityId, |
51: | &$replace, |
52: | ?Closure $callback = null |
53: | ) { |
54: | $this->Provider = $provider; |
55: | $this->Context = $context; |
56: | $this->Entity = $entity; |
57: | $this->EntityId = $entityId; |
58: | |
59: | if ($callback) { |
60: | $this->Callback = $callback; |
61: | } else { |
62: | $this->Replace = &$replace; |
63: | $this->Replace = $this; |
64: | } |
65: | |
66: | $this |
67: | ->getStore() |
68: | ->registerEntityType($entity) |
69: | ->deferEntity( |
70: | $this->Provider->getProviderId(), |
71: | $entity, |
72: | $entityId, |
73: | $this, |
74: | ); |
75: | } |
76: | |
77: | |
78: | |
79: | |
80: | public function toLink(int $type = LinkType::DEFAULT, bool $compact = true): array |
81: | { |
82: | switch ($type) { |
83: | case LinkType::DEFAULT: |
84: | case LinkType::FRIENDLY: |
85: | return [ |
86: | '@type' => $this->getTypeUri($compact), |
87: | '@id' => $this->EntityId, |
88: | ]; |
89: | |
90: | case LinkType::COMPACT: |
91: | return [ |
92: | '@id' => $this->getUri($compact), |
93: | ]; |
94: | |
95: | default: |
96: | throw new LogicException("Invalid link type: $type"); |
97: | } |
98: | } |
99: | |
100: | |
101: | |
102: | |
103: | public function getUri(bool $compact = true): string |
104: | { |
105: | return sprintf('%s/%s', $this->getTypeUri($compact), $this->EntityId); |
106: | } |
107: | |
108: | private function getTypeUri(bool $compact): string |
109: | { |
110: | return $this->getStore()->getEntityTypeUri($this->Entity, $compact); |
111: | } |
112: | |
113: | |
114: | |
115: | |
116: | public function resolve(): SyncEntityInterface |
117: | { |
118: | if ($this->Resolved !== null) { |
119: | return $this->Resolved; |
120: | } |
121: | |
122: | return $this |
123: | ->Provider |
124: | ->with($this->Entity, $this->Context) |
125: | ->get($this->EntityId); |
126: | } |
127: | |
128: | |
129: | |
130: | |
131: | public function replace(SyncEntityInterface $entity): void |
132: | { |
133: | if ($this->Resolved !== null) { |
134: | |
135: | throw new LogicException('Entity already resolved'); |
136: | |
137: | } |
138: | |
139: | $this->Resolved = $entity; |
140: | |
141: | if ($this->Callback) { |
142: | ($this->Callback)($entity); |
143: | return; |
144: | } |
145: | |
146: | $this->Replace = $entity; |
147: | unset($this->Replace); |
148: | } |
149: | |
150: | |
151: | |
152: | |
153: | public static function defer( |
154: | SyncProviderInterface $provider, |
155: | ?SyncContextInterface $context, |
156: | string $entity, |
157: | $entityId, |
158: | &$replace = null, |
159: | ?Closure $callback = null |
160: | ): void { |
161: | new self( |
162: | $provider, |
163: | $context, |
164: | $entity, |
165: | $entityId, |
166: | $replace, |
167: | $callback, |
168: | ); |
169: | } |
170: | |
171: | |
172: | |
173: | |
174: | public static function deferList( |
175: | SyncProviderInterface $provider, |
176: | ?SyncContextInterface $context, |
177: | string $entity, |
178: | array $entityIds, |
179: | &$replace = null, |
180: | ?Closure $callback = null |
181: | ): void { |
182: | if ($callback) { |
183: | foreach ($entityIds as $entityId) { |
184: | |
185: | new self( |
186: | $provider, |
187: | $context, |
188: | $entity, |
189: | $entityId, |
190: | $null, |
191: | $callback, |
192: | ); |
193: | } |
194: | return; |
195: | } |
196: | |
197: | $list = []; |
198: | $i = 0; |
199: | foreach ($entityIds as $entityId) { |
200: | new self( |
201: | $provider, |
202: | $context, |
203: | $entity, |
204: | $entityId, |
205: | $list[$i++], |
206: | ); |
207: | } |
208: | $replace = $list; |
209: | } |
210: | |
211: | |
212: | |
213: | |
214: | public function getContext(): ?SyncContextInterface |
215: | { |
216: | return $this->Context; |
217: | } |
218: | |
219: | private function getStore(): SyncStoreInterface |
220: | { |
221: | return $this->Provider->getStore(); |
222: | } |
223: | |
224: | |
225: | |
226: | |
227: | public function __set(string $name, $value): void |
228: | { |
229: | $entity = $this->resolve(); |
230: | $entity->{$name} = $value; |
231: | } |
232: | |
233: | |
234: | |
235: | |
236: | public function __get(string $name) |
237: | { |
238: | $entity = $this->resolve(); |
239: | return $entity->{$name}; |
240: | } |
241: | |
242: | public function __isset(string $name): bool |
243: | { |
244: | $entity = $this->resolve(); |
245: | return isset($entity->{$name}); |
246: | } |
247: | |
248: | public function __unset(string $name): void |
249: | { |
250: | $entity = $this->resolve(); |
251: | unset($entity->{$name}); |
252: | } |
253: | } |
254: | |