1: <?php
2:
3: declare(strict_types=1);
4:
5: namespace LaravelUi5\OData\Service\Cache;
6:
7: use LaravelUi5\OData\Service\Contracts\ODataServiceInterface;
8: use LaravelUi5\OData\Service\Resolver\CustomBinding;
9: use LaravelUi5\OData\Service\Resolver\EloquentBinding;
10: use LaravelUi5\OData\Service\Resolver\ResolverMap;
11: use LaravelUi5\OData\Service\Resolver\SqlBinding;
12: use LaravelUi5\OData\Service\Resolver\SqlSourceBinding;
13: use ReflectionClass;
14:
15: /**
16: * Generates a PHP file containing a cached ResolverMap for a service.
17: *
18: * The generated file is a readonly class with a static load() method that
19: * reconstructs the ResolverMap from plain PHP — no reflection, no DB calls.
20: */
21: final class ResolverMapWriter
22: {
23: /**
24: * Write the ResolverMap as a PHP file to the service's Edm/ cache directory.
25: */
26: public static function write(ODataServiceInterface $service, ResolverMap $map): void
27: {
28: $refl = new ReflectionClass($service);
29: $namespace = $refl->getNamespaceName() . '\\Edm';
30: $dir = dirname($refl->getFileName()) . '/Edm';
31:
32: if (!is_dir($dir)) {
33: mkdir($dir, 0755, true);
34: }
35:
36: $bindings = self::renderBindings($map);
37:
38: $php = <<<PHP
39: <?php
40:
41: declare(strict_types=1);
42:
43: namespace {$namespace};
44:
45: use LaravelUi5\\OData\\Service\\Resolver\\CustomBinding;
46: use LaravelUi5\\OData\\Service\\Resolver\\EloquentBinding;
47: use LaravelUi5\\OData\\Service\\Resolver\\ResolverMap as BaseResolverMap;
48: use LaravelUi5\\OData\\Service\\Resolver\\SqlBinding;
49: use LaravelUi5\\OData\\Service\\Resolver\\SqlSourceBinding;
50:
51: /**
52: * Generated by odata:cache — do not edit.
53: */
54: final readonly class ResolverMap
55: {
56: public static function load(): BaseResolverMap
57: {
58: return new BaseResolverMap([
59: {$bindings}
60: ]);
61: }
62: }
63:
64: PHP;
65:
66: file_put_contents($dir . '/ResolverMap.php', $php);
67: }
68:
69: private static function renderBindings(ResolverMap $map): string
70: {
71: $lines = [];
72:
73: foreach ($map->getBindings() as $entitySetName => $binding) {
74: $key = var_export($entitySetName, true);
75:
76: $line = match (true) {
77: $binding instanceof EloquentBinding => sprintf(
78: " %s => new EloquentBinding(%s),",
79: $key,
80: '\\' . $binding->modelClass . '::class',
81: ),
82: $binding instanceof SqlBinding => $binding->connection !== null
83: ? sprintf(
84: " %s => new SqlBinding(%s, %s),",
85: $key,
86: var_export($binding->table, true),
87: var_export($binding->connection, true),
88: )
89: : sprintf(
90: " %s => new SqlBinding(%s),",
91: $key,
92: var_export($binding->table, true),
93: ),
94: $binding instanceof SqlSourceBinding => sprintf(
95: " %s => new SqlSourceBinding(%s),",
96: $key,
97: '\\' . $binding->sourceClass . '::class',
98: ),
99: $binding instanceof CustomBinding => sprintf(
100: " %s => new CustomBinding(%s),",
101: $key,
102: '\\' . $binding->resolverClass . '::class',
103: ),
104: default => throw new \RuntimeException(
105: sprintf('Unknown binding type: %s', get_class($binding))
106: ),
107: };
108:
109: $lines[] = $line;
110: }
111:
112: return implode("\n", $lines);
113: }
114: }
115: