Skip to content

SQL Resolver

SqlEntitySetResolver resolves OData queries against a SQL data source. It does not require an Eloquent model and is designed for ValueHelp scenarios, reporting views, and joined queries.

The resolver takes an EntitySetSourceInterface -- any object that provides a fresh Query\Builder via its query() method. This keeps the resolver decoupled from how the query is constructed.

Usage

Via SqlBinding (table or view name)

php
// In registerBindings():
$map->sql($container->getEntitySet('ValueHelp'), 'partner_value_help_view');

// With a specific connection:
$map->sql($container->getEntitySet('ReportData'), 'report_view', connection: 'reporting');

Via SqlSourceBinding (dependency-injected source)

For sources that need implicit filters (tenant scoping, user permissions):

php
// In registerBindings():
$map->sqlSource($container->getEntitySet('FilteredPartners'), PartnerSource::class);

Where PartnerSource implements EntitySetSourceInterface:

php
final readonly class PartnerSource implements EntitySetSourceInterface
{
    public function __construct(private TenantContext $tenant) {}

    public function query(): Builder
    {
        return DB::table('partners')->where('tenant_id', $this->tenant->id);
    }
}

Direct construction

php
use LaravelUi5\OData\Driver\Sql\SqlEntitySetResolver;
use LaravelUi5\OData\Service\Contracts\EntitySetSourceInterface;

$source = new class implements EntitySetSourceInterface {
    public function query(): Builder
    {
        return DB::table('partners')
            ->join('addresses', 'partners.id', '=', 'addresses.partner_id')
            ->select('partners.id', 'partners.name', 'addresses.city');
    }
};

$builder->bindEntitySet(
    $container->getEntitySet('PartnerCities'),
    new SqlEntitySetResolver($source),
);

Constructor

php
new SqlEntitySetResolver(EntitySetSourceInterface $source)
ParameterTypePurpose
$sourceEntitySetSourceInterfaceProvides a fresh Query\Builder via query()

The source's query() method is called on each request to produce a fresh builder. OData system query options ($filter, $orderby, etc.) are applied on top.

Supported query options

OptionSupported
$filterYes -- via FilterToQuery visitor
$searchYes -- LIKE on string columns
$selectYes
$orderbyYes
$top / $skipYes
$countYes
$computeYes
$expandNo -- flat data, no relationships

Interfaces implemented

  • EntitySetResolverInterface -- resolve() yields rows, count() returns total
  • EntityResolverInterface -- resolveOne() fetches a single row by key

How results are yielded

Uses cursor() for memory-efficient streaming. Each row is cast from stdClass to an associative array.

Typical use case: ValueHelp

A ValueHelp dialog in SAP UI5 needs a flat list of key/description pairs. Create a database view and expose it:

sql
CREATE VIEW partner_value_help AS
SELECT p.id, p.name, a.city
FROM partners p
JOIN addresses a ON p.id = a.partner_id;
php
// In registerBindings():
$map->sql($container->getEntitySet('PartnerValueHelp'), 'partner_value_help');

The UI5 client can then query:

GET /odata/PartnerValueHelp?$filter=contains(name,'Acme')&$select=id,name,city&$top=20

OData: MIT | Core: BSL 1.1 | SDK: Commercial License