Caching
The library can pre-compile the Edm schema and resolver bindings into PHP classes so that ODataService::schema() skips EdmBuilder, model discovery, and database introspection on warm boot. This is an opcache-friendly optimization for production.
Development-only commands
Both odata:cache and odata:clear are restricted to development environments. They refuse to run in production or staging and exit with an error. The generated Edm/ directory is committed to version control and deployed as-is — no cache commands are run during deployment.
Why?
- The generated Edm classes depend on the schema at the time of generation. Running
odata:cachein production could produce classes inconsistent with the deployed code if the database schema or model code has changed. - The cold path requires database access (for
Schema::getColumns()during discovery). Production servers should never hit the cold path — the committed cache ensures deterministic startup. - Treating the Edm cache like compiled assets (generated locally, committed, deployed) is the safest approach.
Workflow:
- Develop and test on local machine (cold path, no cache)
- When ready to deploy:
php artisan odata:cache - Commit the generated
Edm/directory - Deploy — the warm path loads instantly with no database access
odata:cache
php artisan odata:cacheFor each service returned by the registry's services() method:
- Builds the
EdmxInterfaceviaconfigure()and model discovery - Builds the
ResolverMapviaregisterBindings()and auto-discovered bindings - Uses
EdmxWriterandResolverMapWriterto generate PHP classes - Writes them to an
Edm/directory next to the service class file
For a service at app/OData/TimesheetService.php, the generated files are placed at:
app/OData/
├── TimesheetService.php
└── Edm/
├── Edmx.php ← cached schema structure
├── ResolverMap.php ← cached resolver bindings
├── Types/
│ ├── User.php
│ ├── Project.php
│ └── ...
└── Entities/
├── Users.php
├── Projects.php
└── ...odata:clear
php artisan odata:clearDeletes the generated Edm/ directory for each registered service.
Warm boot path
On each request, ODataService::schema() checks for cached classes first:
1. EdmxLoader::forService() → load cached Edmx
2. ResolverMapLoader::forService() → load cached ResolverMap
3. If both found → warm path:
a. resolverMap.applyTo(runtimeBuilder) → create + bind resolvers
b. bindFunctions(runtimeBuilder) → functions + singletons
c. build() → done
4. If not found → cold path:
a. configure() + discovery + build Edmx
b. registerBindings() + discovery → build ResolverMap
c. resolverMap.applyTo(runtimeBuilder)
d. bindFunctions(runtimeBuilder)
e. build() → doneThe warm path requires no configure(), no Schema::getColumns(), no reflection, and no database access. Both the Edmx and ResolverMap are plain PHP object graphs, autoloaded via PSR-4 alongside the service class and eligible for opcache preloading.
What is cached and what is not
| Cached (Edmx + ResolverMap) | Not cached (runs every boot) |
|---|---|
| Entity types, complex types, enum types | Function/singleton resolvers (bindFunctions()) |
| Properties, navigation properties | Database connections |
| Entity sets, singletons, function imports | EntitySetSource dependency injection |
| Annotations | CustomBinding container resolution |
| Schema structure | |
| Resolver bindings (Eloquent, Custom, SQL, SqlSource) |
Function and singleton resolvers run on every boot via bindFunctions(). Entity set resolver bindings are serialized in the ResolverMap and restored on warm boot without re-running configure() or registerBindings().
For CustomBinding entries, the resolver class is resolved from the Laravel container at runtime, so injected dependencies are always fresh. For SqlSourceBinding entries, the EntitySetSourceInterface class is likewise resolved from the container.
When to cache
- Development: Do not cache. The schema is rebuilt on each request, reflecting code changes immediately.
- Before deployment: Run
odata:cacheon your development machine, commit theEdm/directory, deploy. - After schema changes: Run
odata:clearthenodata:cache, commit the updatedEdm/directory. - Production/staging: Never run
odata:cacheorodata:clear. The commands refuse to execute in these environments.