PHP code example of novabytes / odata-query-parser
1. Go to this page and download the library: Download novabytes/odata-query-parser library . Choose the download type require .
2. Extract the ZIP file and open the index.php.
3. Add this code to the index.php.
<?php
require_once('vendor/autoload.php');
/* Start to develop here. Best regards https://php-download.com/ */
novabytes / odata-query-parser example snippets
use NovaBytes\OData\Parser\QueryOptionParser;
$query = QueryOptionParser::parse(
'$filter=Price gt 100 and contains(Name,\'Widget\')'
. '&$select=Name,Price'
. '&$expand=Category($select=Name;$top=5)'
. '&$orderby=Price desc'
. '&$top=50&$skip=10&$count=true'
);
$query->filter; // BinaryExpression (and)
$query->select; // [SelectItem('Name'), SelectItem('Price')]
$query->expand; // [ExpandItem('Category', nestedOptions: ...)]
$query->orderby; // [OrderByItem(PropertyPath('Price'), Desc)]
$query->top; // 50
$query->skip; // 10
$query->count; // true
use NovaBytes\OData\Parser\FilterParser;
use NovaBytes\OData\Parser\SelectParser;
use NovaBytes\OData\Parser\OrderByParser;
$filter = FilterParser::parse('Price gt 100 and contains(Name,\'Widget\')');
$select = SelectParser::parse('Name,Price,Address/City');
$orderby = OrderByParser::parse('Name asc,Price desc');
// Comparison operators: eq, ne, gt, ge, lt, le
FilterParser::parse('Price gt 100');
FilterParser::parse('Name eq \'Milk\'');
// Logical operators: and, or, not
FilterParser::parse('Price gt 5 and Price lt 20');
FilterParser::parse('not contains(Name,\'test\')');
// Arithmetic operators: add, sub, mul, div, divby, mod
FilterParser::parse('Price mul Quantity gt 1000');
// Grouping with parentheses
FilterParser::parse('(Name eq \'A\' or Name eq \'B\') and Price lt 10');
// Property paths
FilterParser::parse('Address/City eq \'London\'');
// The in operator
FilterParser::parse('Name in (\'Milk\',\'Cheese\',\'Butter\')');
// String functions
FilterParser::parse('contains(Name,\'milk\')');
FilterParser::parse('startswith(Name,\'Ch\')');
FilterParser::parse('endswith(Name,\'ilk\')');
FilterParser::parse('length(Name) gt 5');
FilterParser::parse('indexof(Name,\'lk\') eq 2');
FilterParser::parse('substring(Name,1,3) eq \'ilk\'');
FilterParser::parse('tolower(Name) eq \'milk\'');
FilterParser::parse('toupper(Name) eq \'MILK\'');
FilterParser::parse('trim(Name) eq \'Milk\'');
FilterParser::parse('concat(FirstName,LastName) eq \'JohnDoe\'');
// Date/time functions
FilterParser::parse('year(BirthDate) eq 1990');
FilterParser::parse('month(BirthDate) eq 3');
FilterParser::parse('day(BirthDate) eq 20');
FilterParser::parse('hour(StartTime) ge 9');
FilterParser::parse('Date gt now()');
// Math functions
FilterParser::parse('round(Price) eq 10');
FilterParser::parse('floor(Price) eq 9');
FilterParser::parse('ceiling(Price) eq 10');
// any — true if any element matches
FilterParser::parse('Items/any(d:d/Qty gt 100)');
// any without predicate — true if collection is non-empty
FilterParser::parse('Tags/any()');
// all — true if all elements match
FilterParser::parse('Items/all(d:d/Price gt 0)');
FilterParser::parse('Active eq true'); // boolean
FilterParser::parse('Name eq null'); // null
FilterParser::parse('Count eq 42'); // integer
FilterParser::parse('Price lt 9.99'); // decimal
FilterParser::parse('Name eq \'O\'\'Brien\''); // string (escaped quotes)
FilterParser::parse('Id eq 01234567-89ab-cdef-0123-456789abcdef'); // GUID
FilterParser::parse('BirthDate eq 2023-01-15'); // date
FilterParser::parse('Created eq 2023-01-15T14:30:00Z'); // DateTimeOffset
FilterParser::parse('Duration eq duration\'P1DT2H30M\''); // duration
$items = SelectParser::parse('Name,Price,Address/City');
// [SelectItem(['Name']), SelectItem(['Price']), SelectItem(['Address', 'City'])]
$items = SelectParser::parse('*');
// [SelectItem([], isWildcard: true)]
use NovaBytes\OData\Parser\ExpandParser;
$items = ExpandParser::parse('Products,Category');
// [ExpandItem(['Products']), ExpandItem(['Category'])]
// With nested query options (semicolon-separated inside parentheses)
$items = ExpandParser::parse('Products($filter=Price gt 100;$select=Name;$top=5)');
// ExpandItem(['Products'], nestedOptions: QueryOptions(filter: ..., select: ..., top: 5))
$items = OrderByParser::parse('Name asc,Price desc');
// [OrderByItem(PropertyPath('Name'), Asc), OrderByItem(PropertyPath('Price'), Desc)]
// Default direction is ascending
$items = OrderByParser::parse('Name');
// [OrderByItem(PropertyPath('Name'), Asc)]
$query = QueryOptionParser::parse('$top=10&$skip=20&$count=true');
$query->top; // 10
$query->skip; // 20
$query->count; // true
use NovaBytes\OData\Parser\ResourcePathParser;
// Entity set collection
$path = ResourcePathParser::parse('/Products');
$path->entitySet; // 'Products'
$path->key; // null
$path->isSingleEntity(); // false
// Single entity by key
$path = ResourcePathParser::parse('/Products(1)');
$path->key->getSingleValue(); // 1
// String keys
$path = ResourcePathParser::parse("/Products('abc')");
$path->key->getSingleValue(); // 'abc'
// Composite keys
$path = ResourcePathParser::parse('/OrderItems(OrderId=1,ItemId=2)');
$path->key->values; // ['OrderId' => 1, 'ItemId' => 2]
// Navigation segments
$path = ResourcePathParser::parse('/Products(1)/Category');
$path->navigationSegments[0]->property; // 'Category'
// GUID keys
$path = ResourcePathParser::parse('/Products(01234567-89ab-cdef-0123-456789abcdef)');
use NovaBytes\OData\AST\Filter\BinaryExpression;
use NovaBytes\OData\AST\Filter\Literal;
use NovaBytes\OData\AST\Filter\PropertyPath;
use NovaBytes\OData\Visitor\ExpressionVisitor;
class SqlWhereVisitor implements ExpressionVisitor
{
public function visitBinaryExpression(BinaryExpression $expr): string
{
$left = $this->visit($expr->left);
$right = $this->visit($expr->right);
$op = match($expr->operator) {
BinaryOperator::Eq => '=',
BinaryOperator::Ne => '!=',
BinaryOperator::Gt => '>',
// ...
};
return "{$left} {$op} {$right}";
}
public function visitPropertyPath(PropertyPath $expr): string
{
return implode('.', $expr->segments);
}
public function visitLiteral(Literal $expr): string
{
// Use parameterized queries in real code!
return match($expr->type) {
LiteralType::String => "'{$expr->value}'",
LiteralType::Null => 'NULL',
default => (string) $expr->value,
};
}
// ... implement remaining visit methods
}
use NovaBytes\OData\Visitor\StringifyVisitor;
$expr = FilterParser::parse('Price gt 100 and Name eq \'Milk\'');
$visitor = new StringifyVisitor();
echo $visitor->stringify($expr);
// Price gt 100 and Name eq 'Milk'
try {
FilterParser::parse('Price gtt 100');
} catch (ParseException $e) {
$e->getMessage(); // "Unexpected 'gtt' at position 6; expected ..."
$e->position; // 6
}
use NovaBytes\OData\Metadata\EntityType;
use NovaBytes\OData\Metadata\PropertyMetadata;
use NovaBytes\OData\Metadata\NavigationPropertyMetadata;
$product = new EntityType(
name: 'Product',
entitySetName: 'Products',
keyProperty: 'Id',
properties: [
new PropertyMetadata('Id', 'Edm.Int64', nullable: false, filterable: true, sortable: true, selectable: true),
new PropertyMetadata('Name', 'Edm.String', nullable: false, filterable: true, sortable: true, selectable: true, creatable: true, updatable: true),
new PropertyMetadata('Price', 'Edm.Decimal', nullable: false, filterable: true, sortable: true, selectable: true, creatable: true, updatable: true),
],
navigationProperties: [
new NavigationPropertyMetadata('Category', 'Category', isCollection: false),
new NavigationPropertyMetadata('Reviews', 'Review', isCollection: true),
],
operations: ['read', 'create', 'update', 'delete'],
);
use NovaBytes\OData\Metadata\EdmTypeResolver;
EdmTypeResolver::resolve('integer'); // 'Edm.Int32'
EdmTypeResolver::resolve('varchar'); // 'Edm.String'
EdmTypeResolver::resolve('timestamp'); // 'Edm.DateTimeOffset'
EdmTypeResolver::resolve('boolean'); // 'Edm.Boolean'
use NovaBytes\OData\Metadata\CsdlGenerator;
$xml = CsdlGenerator::generate('MyApp', [$product, $category]);
// Returns valid OData v4 CSDL XML with capability annotations
use NovaBytes\OData\Metadata\OpenApiGenerator;
$spec = OpenApiGenerator::generate([$product, $category], [
'title' => 'My OData API',
'version' => '1.0.0',
]);
// Generates:
// GET /Products — list entities
// POST /Products — create entity (with ProductCreate schema)
// GET /Products({Id}) — get single entity
// PUT /Products({Id}) — full replace (with ProductUpdate schema)
// PATCH /Products({Id}) — partial update
// DELETE /Products({Id}) — delete entity
echo json_encode($spec, JSON_PRETTY_PRINT);