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