1: <?php declare(strict_types=1);
2:
3: namespace Salient\Core\Concern;
4:
5: use Salient\Contract\Core\Entity\Providable;
6: use Salient\Contract\Core\Provider\ProviderContextInterface;
7: use Salient\Contract\Core\Provider\ProviderInterface;
8: use Salient\Core\Legacy\Introspector;
9: use LogicException;
10:
11: /**
12: * @api
13: *
14: * @template TProvider of ProviderInterface
15: * @template TContext of ProviderContextInterface
16: *
17: * @phpstan-require-implements Providable<TProvider,TContext>
18: */
19: trait ProvidableTrait
20: {
21: /** @var TProvider|null */
22: private ?ProviderInterface $Provider = null;
23: /** @var TContext|null */
24: private ?ProviderContextInterface $Context = null;
25: /** @var class-string|null */
26: private ?string $Service = null;
27:
28: /**
29: * @param TProvider $provider
30: */
31: public function setProvider(ProviderInterface $provider)
32: {
33: if ($this->Provider) {
34: throw new LogicException('Provider already set');
35: }
36: $this->Provider = $provider;
37: return $this;
38: }
39:
40: /**
41: * @return TProvider|null
42: */
43: public function getProvider(): ?ProviderInterface
44: {
45: return $this->Provider;
46: }
47:
48: /**
49: * @param TContext $context
50: */
51: public function setContext(ProviderContextInterface $context)
52: {
53: $this->Context = $context;
54: return $this;
55: }
56:
57: /**
58: * @return TContext|null
59: */
60: public function getContext(): ?ProviderContextInterface
61: {
62: return $this->Context;
63: }
64:
65: /**
66: * @inheritDoc
67: */
68: public function setService(string $service): void
69: {
70: $this->Service = $service;
71: }
72:
73: /**
74: * @inheritDoc
75: */
76: public function getService(): string
77: {
78: return $this->Service ?? static::class;
79: }
80:
81: /**
82: * @param TContext $context
83: */
84: public static function provide(
85: array $data,
86: ProviderContextInterface $context
87: ) {
88: $provider = $context->getProvider();
89: $container = $context
90: ->getContainer()
91: ->inContextOf(get_class($provider));
92: $context = $context->withContainer($container);
93:
94: $closure = Introspector::getService($container, static::class)
95: ->getCreateProvidableFromClosure();
96:
97: return $closure($data, $provider, $context);
98: }
99:
100: /**
101: * @param TContext $context
102: */
103: public static function provideMultiple(
104: iterable $data,
105: ProviderContextInterface $context,
106: int $conformity = Providable::CONFORMITY_NONE
107: ): iterable {
108: $provider = $context->getProvider();
109: $container = $context
110: ->getContainer()
111: ->inContextOf(get_class($provider));
112: $context = $context->withContainer($container);
113: $conformity = max($context->getConformity(), $conformity);
114: $introspector = Introspector::getService($container, static::class);
115:
116: foreach ($data as $key => $data) {
117: /** @disregard P1012 */
118: $closure ??= $conformity === self::CONFORMITY_PARTIAL || $conformity === self::CONFORMITY_COMPLETE
119: ? $introspector->getCreateProvidableFromSignatureClosure(array_keys($data))
120: : $introspector->getCreateProvidableFromClosure();
121:
122: yield $key => $closure($data, $provider, $context);
123: }
124: }
125:
126: /**
127: * @inheritDoc
128: */
129: public function postLoad(): void {}
130: }
131: