1: <?php declare(strict_types=1);
2:
3: namespace Salient\Core\Provider;
4:
5: use Salient\Contract\Container\ContainerInterface;
6: use Salient\Contract\Core\Entity\Providable;
7: use Salient\Contract\Core\Entity\Treeable;
8: use Salient\Contract\Core\Provider\ProviderContextInterface;
9: use Salient\Contract\Core\Provider\ProviderInterface;
10: use Salient\Contract\Core\HasId;
11: use Salient\Core\Concern\ImmutableTrait;
12: use Salient\Utility\Arr;
13: use Salient\Utility\Get;
14: use Salient\Utility\Str;
15:
16: /**
17: * @api
18: *
19: * @template TProvider of ProviderInterface
20: * @template TEntity of Providable
21: *
22: * @implements ProviderContextInterface<TProvider,TEntity>
23: */
24: class ProviderContext implements ProviderContextInterface
25: {
26: use ImmutableTrait;
27:
28: /** @var TProvider */
29: protected ProviderInterface $Provider;
30: protected ContainerInterface $Container;
31: /** @var class-string<TEntity>|null */
32: protected ?string $EntityType = null;
33: /** @var self::* */
34: protected int $Conformity = self::CONFORMITY_NONE;
35: /** @var TEntity[] */
36: protected array $Entities = [];
37: /** @var (TEntity&Treeable)|null */
38: protected ?Treeable $Parent = null;
39: /** @var array<string,(int|string|float|bool|null)[]|int|string|float|bool|null> */
40: protected array $Values = [];
41:
42: /**
43: * @api
44: *
45: * @param TProvider $provider
46: */
47: public function __construct(
48: ProviderInterface $provider,
49: ContainerInterface $container
50: ) {
51: $this->Provider = $provider;
52: $this->Container = $container;
53: }
54:
55: /**
56: * @inheritDoc
57: */
58: public function getProvider(): ProviderInterface
59: {
60: return $this->Provider;
61: }
62:
63: /**
64: * @inheritDoc
65: */
66: public function getContainer(): ContainerInterface
67: {
68: return $this->Container;
69: }
70:
71: /**
72: * @inheritDoc
73: */
74: public function withContainer(ContainerInterface $container)
75: {
76: return $this->with('Container', $container);
77: }
78:
79: /**
80: * @inheritDoc
81: */
82: public function getEntityType(): ?string
83: {
84: return $this->EntityType;
85: }
86:
87: /**
88: * @inheritDoc
89: */
90: public function withEntityType(string $entityType)
91: {
92: return $this->with('EntityType', $entityType);
93: }
94:
95: /**
96: * @inheritDoc
97: */
98: public function getConformity(): int
99: {
100: return $this->Conformity;
101: }
102:
103: /**
104: * @inheritDoc
105: */
106: public function withConformity(int $conformity)
107: {
108: return $this->with('Conformity', $conformity);
109: }
110:
111: /**
112: * @inheritDoc
113: */
114: public function getEntities(): array
115: {
116: return $this->Entities;
117: }
118:
119: /**
120: * @inheritDoc
121: */
122: public function getLastEntity(): ?Providable
123: {
124: return Arr::last($this->Entities);
125: }
126:
127: /**
128: * @inheritDoc
129: */
130: public function pushEntity($entity)
131: {
132: $clone = clone $this;
133: $clone->Entities[] = $entity;
134:
135: if ($entity instanceof HasId) {
136: $id = $entity->getId();
137: if ($id !== null) {
138: $name = Get::basename(get_class($entity));
139: return $clone->withValue("{$name}_id", $id);
140: }
141: }
142:
143: return $clone;
144: }
145:
146: /**
147: * @inheritDoc
148: */
149: public function getParent(): ?Providable
150: {
151: return $this->Parent;
152: }
153:
154: /**
155: * @inheritDoc
156: */
157: public function withParent(?Treeable $parent)
158: {
159: return $this->with('Parent', $parent);
160: }
161:
162: /**
163: * @inheritDoc
164: */
165: public function hasValue(string $name): bool
166: {
167: $name = Str::snake($name);
168:
169: if (array_key_exists($name, $this->Values)) {
170: return true;
171: }
172:
173: if (substr($name, -3) !== '_id') {
174: return false;
175: }
176:
177: $name = Str::snake(substr($name, 0, -3));
178:
179: return array_key_exists($name, $this->Values);
180: }
181:
182: /**
183: * @inheritDoc
184: */
185: public function getValue(string $name)
186: {
187: $name = Str::snake($name);
188:
189: if (array_key_exists($name, $this->Values)) {
190: return $this->Values[$name];
191: }
192:
193: if (substr($name, -3) !== '_id') {
194: return null;
195: }
196:
197: $name = Str::snake(substr($name, 0, -3));
198:
199: return $this->Values[$name] ?? null;
200: }
201:
202: /**
203: * @inheritDoc
204: */
205: public function withValue(string $name, $value)
206: {
207: $name = Str::snake($name);
208: $values = $this->Values;
209: $values[$name] = $value;
210:
211: if (substr($name, -3) === '_id') {
212: $name = Str::snake(substr($name, 0, -3));
213: $values[$name] = $value;
214: }
215:
216: return $this->with('Values', $values);
217: }
218: }
219: