1: <?php
2:
3: declare(strict_types=1);
4:
5: namespace LaravelUi5\OData\Protocol\Execution;
6:
7: use LaravelUi5\OData\Http\ODataResponse;
8: use LaravelUi5\OData\Protocol\Planning\FunctionInvocationPlan;
9: use LaravelUi5\OData\Service\Contracts\RuntimeSchemaInterface;
10:
11: /**
12: * Handles FunctionInvocationPlan — executes a function import and returns
13: * the result as JSON.
14: *
15: * The function resolver is looked up from RuntimeSchema by the
16: * FunctionImportInterface object reference on the plan.
17: */
18: final readonly class FunctionInvocationHandler
19: {
20: public function __construct(
21: private RuntimeSchemaInterface $schema,
22: private string $serviceRoot,
23: ) {}
24:
25: public function handle(FunctionInvocationPlan $plan): ODataResponse
26: {
27: $resolver = $this->schema->getFunctionResolver($plan->import);
28: $result = $resolver->resolve($plan);
29: $context = $this->serviceRoot . '$metadata#' . $plan->import->getName();
30:
31: $response = new ODataResponse(null, 200, [
32: 'Content-Type' => 'application/json;odata.metadata=minimal;charset=utf-8',
33: 'OData-Version' => '4.0',
34: ]);
35:
36: $response->setCallback(static function () use ($context, $result): void {
37: if (is_array($result) || is_object($result)) {
38: $payload = array_merge(['@odata.context' => $context], (array) $result);
39: echo json_encode($payload, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
40: } else {
41: echo json_encode(
42: ['@odata.context' => $context, 'value' => $result],
43: JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE
44: );
45: }
46: });
47:
48: return $response;
49: }
50: }
51: