Skip to content

Commit 56ccf68

Browse files
committed
Fix: Add serviceUri() to ServiceEndpointInterface and clarify endpoint routing docs
- Introduced new method serviceUri(): string to explicitly declare the logical URI segment for each OData endpoint - Updated ServiceEndpointInterface PHPDoc to reflect modular, config-driven routing - Clarified semantics of endpoint() and route() to match actual behavior in Endpoint base class - Aligns terminology with ServiceProvider::boot() logic for endpoint resolution
1 parent 3b2dee5 commit 56ccf68

File tree

3 files changed

+63
-14
lines changed

3 files changed

+63
-14
lines changed

src/Endpoint.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,19 @@ public function __construct(string $serviceUri)
1717
$this->serviceUri = trim($serviceUri, '/');
1818

1919
$prefix = rtrim(config('lodata.prefix'), '/');
20-
$this->route = ('' === $serviceUri)
20+
21+
$this->route = ('' === $this->serviceUri)
2122
? $prefix
2223
: $prefix . '/' . $this->serviceUri;
2324

2425
$this->endpoint = url($this->route) . '/';
2526
}
2627

28+
public function serviceUri(): string
29+
{
30+
return $this->serviceUri;
31+
}
32+
2733
public function endpoint(): string
2834
{
2935
return $this->endpoint;

src/Interfaces/ServiceEndpointInterface.php

Lines changed: 48 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,68 @@
55
use Flat3\Lodata\Model;
66

77
/**
8-
* Interface for defining a custom OData service endpoint.
8+
* Interface for defining a modular OData service endpoint in Laravel.
99
*
10-
* Implementers can use this interface to expose a specific service under a custom path,
11-
* define its namespace, route behavior, and optionally provide a statically generated
12-
* $metadata document.
10+
* Implementers of this interface represent individually addressable OData services.
11+
* Each mounted under its own URI segment and backed by a schema model.
12+
*
13+
* This enables clean separation of business domains and supports multi-endpoint
14+
* discovery for modular application design.
15+
*
16+
* Configuration versus Declaration
17+
* --------------------------------
18+
* The public URI segment used to expose a service is NOT determined by the
19+
* implementing class itself, but by the service map in `config/lodata.php`:
20+
*
21+
* ```php
22+
* 'endpoints' => [
23+
* 'users' => \App\OData\UsersEndpoint::class,
24+
* 'budgets' => \App\OData\BudgetsEndpoint::class,
25+
* ]
26+
* ```
27+
*
28+
* This keeps the routing surface under application control, and avoids
29+
* conflicts when two modules declare the same internal segment.
30+
*
31+
* To implement an endpoint:
32+
* - Extend `Flat3\Lodata\Endpoint` or implement this interface directly
33+
* - Register the class in `config/lodata.php` under a unique segment key
34+
* - Define the `discover()` method to expose entities via OData
1335
*/
1436
interface ServiceEndpointInterface
1537
{
38+
/**
39+
* Returns the ServiceURI segment name for this OData endpoint.
40+
*
41+
* This value is used in routing and metadata resolution. It Must be globally unique.
42+
*
43+
* @return string The segment (path identifier) of the endpoint
44+
*/
45+
public function serviceUri(): string;
1646

1747
/**
18-
* Returns the relative endpoint identifier within the OData service URI space.
48+
* Returns the fully qualified URL for this OData endpoint.
1949
*
20-
* This is the part that appears between the configured Lodata prefix and
21-
* the `$metadata` segment, e.g.:
22-
* https://<server>:<port>/<config('lodata.prefix')>/<endpoint>/$metadata
50+
* This includes the application host, port, and the configured segment,
51+
* https://<server>:<port>/<config('lodata.prefix')>/<service-uri>/,
52+
* Example: https://example.com/odata/users/
2353
*
24-
* @return string The relative OData endpoint path
54+
* This URL forms the base of the OData service space, and is used for navigation links
55+
* and metadata discovery.
56+
*
57+
* @return string The full URL of the service endpoint
2558
*/
2659
public function endpoint(): string;
2760

2861
/**
29-
* Returns the full request route to this service endpoint.
62+
* Returns the internal Laravel route path for this OData service endpoint.
63+
*
64+
* This is the relative URI path that Laravel uses to match incoming requests,
65+
* typically composed of the configured Lodata prefix and the service segment.
3066
*
31-
* This typically resolves to the route path used by Laravel to handle
32-
* incoming requests for this specific service instance.
67+
* Example: "odata/users"
3368
*
34-
* @return string The full HTTP route to the endpoint
69+
* @return string Relative route path for the endpoint
3570
*/
3671
public function route(): string;
3772

src/ServiceProvider.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Flat3\Lodata;
66

7+
use RuntimeException;
78
use Composer\InstalledVersions;
89
use Flat3\Lodata\Controller\Monitor;
910
use Flat3\Lodata\Controller\OData;
@@ -14,6 +15,7 @@
1415
use Flat3\Lodata\Helper\Flysystem;
1516
use Flat3\Lodata\Helper\DBAL;
1617
use Flat3\Lodata\Helper\Symfony;
18+
use Flat3\Lodata\Interfaces\ServiceEndpointInterface;
1719
use Illuminate\Foundation\Application;
1820
use Illuminate\Support\Facades\Route;
1921
use Symfony\Component\HttpKernel\Kernel;
@@ -64,6 +66,12 @@ public function boot()
6466
}
6567
else if (array_key_exists($segments[1], $serviceUris)) {
6668
$clazz = $serviceUris[$segments[1]];
69+
if (!class_exists($clazz)) {
70+
throw new RuntimeException(sprintf('Endpoint class `%s` does not exist', $clazz));
71+
}
72+
if (!is_subclass_of($clazz, ServiceEndpointInterface::class)) {
73+
throw new RuntimeException(sprintf('Endpoint class `%s` must implement Flat3\\Lodata\\Interfaces\\ServiceEndpointInterface', $clazz));
74+
}
6775
$service = new $clazz($segments[1]);
6876
}
6977
else {

0 commit comments

Comments
 (0)