1: <?php
2:
3: declare(strict_types=1);
4:
5: namespace LaravelUi5\OData\Service\Cache;
6:
7: use LaravelUi5\OData\Edm\Contracts\EdmxInterface;
8: use LaravelUi5\OData\Service\Contracts\ODataServiceInterface;
9: use ReflectionClass;
10:
11: /**
12: * Loads a cached EdmxInterface from the generated Edm\ directory next to a service class.
13: *
14: * The cache is a set of PHP readonly classes generated by EdmxWriter. The root class
15: * is always {ServiceNamespace}\Edm\Edmx and lives at {ServiceDir}/Edm/Edmx.php.
16: */
17: final class EdmxLoader
18: {
19: /**
20: * Attempt to load a cached EdmxInterface for the given service.
21: *
22: * Returns null when no cache exists (the service should fall back to EdmBuilder).
23: */
24: public static function forService(ODataServiceInterface $service): ?EdmxInterface
25: {
26: // Check the file exists before class_exists() to avoid autoloader
27: // errors when the cache directory has been cleared but the in-memory
28: // classmap still references the deleted files.
29: $cacheFile = self::cacheDir($service) . '/Edmx.php';
30: if (!file_exists($cacheFile)) {
31: return null;
32: }
33:
34: $edmxClass = self::edmxClassName($service);
35:
36: if (!class_exists($edmxClass)) {
37: return null;
38: }
39:
40: $instance = new $edmxClass();
41:
42: return $instance instanceof EdmxInterface ? $instance : null;
43: }
44:
45: /**
46: * Derive the FQCN of the cached Edmx class from a service instance.
47: *
48: * Convention: {ServiceClassNamespace}\Edm\Edmx
49: */
50: public static function edmxClassName(ODataServiceInterface $service): string
51: {
52: $refl = new ReflectionClass($service);
53: return $refl->getNamespaceName() . '\\Edm\\Edmx';
54: }
55:
56: /**
57: * Derive the filesystem directory where cached Edm files live.
58: *
59: * Convention: {ServiceClassDir}/Edm/
60: */
61: public static function cacheDir(ODataServiceInterface $service): string
62: {
63: $refl = new ReflectionClass($service);
64: return dirname($refl->getFileName()) . '/Edm';
65: }
66: }
67: