adrotec/odataphpprod
Unmaintained PHP OData (v2) producer/server library for exposing read-only data sources. Supports Atom and JSON, $metadata, feeds/entries/properties, paging and query options ($filter, $select, $expand, $orderby, $top, $skip), plus optional media streaming.
Installation
composer require adrotec/odataphpprod:^1.1.0
Add the service provider to config/app.php:
'providers' => [
// ...
Adrotec\ODataPhpProd\ODataPhpProdServiceProvider::class,
],
Basic Route Definition
Define an OData route in routes/web.php or routes/api.php:
Route::odata('/odata', function() {
return new \Adrotec\ODataPhpProd\ODataController();
});
First Use Case: Simple Entity Exposure
Create a model (e.g., Product) and expose it via OData:
use Adrotec\ODataPhpProd\ODataModel;
class Product extends Model implements ODataModel
{
public static function getODataProperties()
{
return [
'id' => 'id',
'name' => 'name',
'price' => 'price',
];
}
}
Access via:
GET /odata/Products
(Unchanged from previous version)
CRUD Operations
/odata/Products (GET)/odata/Products (POST with JSON payload)/odata/Products(1) (PATCH/PUT)/odata/Products(1) (DELETE)Querying with OData Syntax Filter:
GET /odata/Products?$filter=price gt 100
Ordering:
GET /odata/Products?$orderby=name desc
Paging:
GET /odata/Products?$top=10&$skip=20
Relationships
Define relationships in getODataProperties():
public static function getODataProperties()
{
return [
'id' => 'id',
'category' => [
'entity' => 'Category',
'foreignKey' => 'category_id',
],
];
}
Access via:
GET /odata/Products(1)/category
Custom Actions
Define actions in getODataActions():
public static function getODataActions()
{
return [
'getDiscountedPrice' => [
'httpMethod' => 'GET',
'parameters' => [
'discountPercentage' => ['type' => 'Edm.Double'],
],
],
];
}
Invoke via:
POST /odata/Products(1)/getDiscountedPrice(discountPercentage=20)
Integration with Laravel Eloquent Use Eloquent models directly:
class ProductController extends ODataController
{
protected $model = \App\Models\Product::class;
}
(Unchanged from previous version)
Authentication/Middleware Apply middleware to OData routes:
Route::odata('/odata', function() {
return new \Adrotec\ODataPhpProd\ODataController();
})->middleware('auth:api');
CORS Configuration Ensure CORS headers are set for OData endpoints if used in SPAs:
Route::middleware('cors:api')->odata('/odata', ...);
Validation Use Laravel’s validation for custom actions:
public function getDiscountedPrice($key, $parameters)
{
$validator = Validator::make($parameters, [
'discountPercentage' => 'required|numeric|min:0|max:100',
]);
// ...
}
Logging Log OData requests for debugging:
Route::odata('/odata', function() {
\Log::info('OData request received');
return new \Adrotec\ODataPhpProd\ODataController();
});
Deprecated Package
No Built-in Caching
$cacheKey = 'odata_products_' . md5($request->getQueryString());
return Cache::remember($cacheKey, now()->addMinutes(10), function() use ($request) {
return $this->query($request);
});
Limited Laravel Integration
public function query($request)
{
$query = parent::query($request);
return $query->withTrashed(); // Example for soft deletes
}
No Built-in Error Handling
public function handleError($exception)
{
return response()->json([
'error' => $exception->getMessage(),
], 500);
}
Performance with Complex Queries
$expand with deep relationships without limits:
GET /odata/Products?$expand=category($expand=supplier)
Reserved Keyword in Metadata Types
String class in ODataProducer\Providers\Metadata\Type was renamed to StringType in 1.1.0 due to PHP7+ reserved keywords.String class must be updated to StringType.use ODataProducer\Providers\Metadata\Type\String;
with:
use ODataProducer\Providers\Metadata\Type\StringType;
(Unchanged from previous version)
Enable Query Logging
Add to AppServiceProvider:
public function boot()
{
\DB::enableQueryLog();
}
Log queries in OData actions:
\Log::debug('Query:', \DB::getQueryLog());
Validate OData Syntax Use tools like OData Validator to test queries before implementing.
Check Request Payloads For POST/PATCH, log raw input:
\Log::debug('Request payload:', $request->getContent());
(Unchanged from previous version, except for updated namespace)
Custom Metadata
Extend getODataMetadata() for custom EDM definitions:
public static function getODataMetadata()
{
return [
'namespace' => 'MyNamespace',
'entities' => [
'Product' => [
'properties' => [
'id' => ['type' => 'Edm.Int32'],
'name' => ['type' => 'Edm.String'], // Use 'Edm.String' instead of 'String'
],
],
],
];
}
Dynamic Properties Use closures for dynamic properties:
public static function getODataProperties()
{
return [
'id' => 'id',
'formattedPrice' => function($model) {
return '$' . number_format($model->price, 2);
},
];
}
Override Default Behavior Extend the base controller:
class CustomODataController extends \Adrotec\ODataPhpProd\ODataController
{
public function query($request)
{
$query = parent::query($request);
// Add global scope or filters
return $query->where('active', 1);
}
}
Add Custom Providers
Register additional OData providers in ODataPhpProdServiceProvider:
$this->app->bind(
\Adrotec\ODataPhpProd\ODataProvider::class,
\App\Providers\CustomODataProvider::class
);
StringType class.How can I help you explore Laravel packages today?