bankiru/doctrine-api-client
Doctrine-style entity manager for remote RPC APIs. Map entities via YAML, register RPC clients, and use Doctrine Common interfaces (metadata, proxies, repositories) to fetch and manage remote resources as if they were Doctrine entities.
Install the Package:
composer require bankiru/doctrine-api-client
Define an Entity Class:
Create a Doctrine entity class with RPC-compatible properties (e.g., MyVendor\Api\Entity\MyEntity).
namespace MyVendor\Api\Entity;
class MyEntity {
private $id;
private $payload;
public function getId() { return $this->id; }
public function getPayload() { return $this->payload; }
}
Configure Metadata:
Create a YAML file (Resources/config/api/MyEntity.api.yml) to map the entity to RPC methods:
MyVendor\Api\Entity\MyEntity:
type: entity
id:
id:
type: int
fields:
payload:
type: string
client:
name: my-client
entityPath: my-entity
Set Up the EntityManager:
Initialize the EntityManager with a custom RpcClient and metadata driver:
use Bankiru\Api\Doctrine\Configuration;
use Bankiru\Api\Doctrine\Mapping\Driver\YmlMetadataDriver;
use Bankiru\Api\Doctrine\Mapping\Driver\MappingDriverChain;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Cache\FilesystemCache;
use Doctrine\Common\Persistence\Mapping\Driver\SymfonyFileLocator;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Mapping\Driver\AnnotationDriver;
use Doctrine\ORM\Mapping\Driver\DriverChain;
$client = new RpcClient(); // Implement RpcClientInterface
$registry = new ClientRegistry();
$registry->add('my-client', $client);
$configuration = new Configuration();
$configuration->setRegistry($registry);
$configuration->setProxyDir(__DIR__ . '/cache/doctrine/proxy');
$configuration->setProxyNamespace('MyVendor\Api\Proxy');
$driver = new MappingDriverChain();
$driver->addDriver(
new YmlMetadataDriver(
new SymfonyFileLocator(
[__DIR__ . '/../Resources/config/api/' => 'MyVendor\Api\Entity'],
'.api.yml',
DIRECTORY_SEPARATOR
)
),
'MyVendor\Api\Entity'
);
$configuration->setDriver($driver);
$entityManager = new EntityManager($configuration);
Query Entities:
Use the EntityManager to fetch entities via RPC:
$samples = $entityManager->getRepository(MyEntity::class)->findBy(['payload' => 'sample']);
foreach ($samples as $sample) {
echo $sample->getId();
}
Leverage the package to treat remote RPC data as local Doctrine entities. For example:
User entity with RPC-mapped fields.EntityManager to point to the RPC client.findBy or custom repository methods, and access their data as if it were local.find(), findBy(), and findOneBy() as you would with a local database.$user = $entityManager->getRepository(User::class)->find(1);
$users = $entityManager->getRepository(User::class)->findBy(['active' => true]);
user/find?id=1).EntityRepository to add RPC-specific methods.class UserRepository extends \Bankiru\Api\Doctrine\EntityRepository {
public function getActiveUsersWithRoles() {
$request = new \Bankiru\Api\Rpc\RpcRequest(
$this->getClientMethod('users-with-roles'),
['active' => true]
);
return $this->getClient()->invoke([$request])->getResponse($request);
}
}
MyVendor\Api\Entity\User:
repositoryClass: MyVendor\Api\Repository\UserRepository
manyToOne, oneToMany, etc., in YAML to model relationships across RPC services.MyVendor\Api\Entity\User:
manyToOne:
profile:
target: MyVendor\Api\Entity\Profile
inversedBy: users
$user->getProfile() triggers an RPC call).Entity[]|ArrayCollection for collections.$typeRegistry = $configuration->getTypeRegistry();
$typeRegistry->add('custom_type', new CustomType());
EntityManager to Laravel’s service container.// In a Laravel service provider
$this->app->singleton(EntityManager::class, function ($app) {
$configuration = new Configuration();
// ... configure as above ...
return new EntityManager($configuration);
});
use Illuminate\Support\Facades\App;
$users = App::make(EntityManager::class)
->getRepository(User::class)
->findBy(['active' => true]);
EntityManager and bind it to the container:
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Doctrine\ORM\EntityManager;
class DoctrineApiProvider extends ServiceProvider {
public function register() {
$this->app->singleton(EntityManager::class, function ($app) {
$configuration = new Configuration();
// ... setup configuration ...
return new EntityManager($configuration);
});
}
}
config/app.php:
'providers' => [
// ...
App\Providers\DoctrineApiProvider::class,
],
RpcClient to include auth headers or tokens.class AuthRpcClient implements RpcClientInterface {
private $client;
public function __construct() {
$this->client = new RpcClient();
$this->client->setAuthToken('your_token_here');
}
public function invoke(array $requests) {
// Add auth headers to each request
foreach ($requests as $request) {
$request->addHeader('Authorization', 'Bearer your_token_here');
}
return $this->client->invoke($requests);
}
}
class CachingRepository extends EntityRepository {
public function find($id) {
$cacheKey = "api_user_{$id}";
if (cache()->has($cacheKey)) {
return cache()->get($cacheKey);
}
$user = parent::find($id);
cache()->put($cacheKey, $user, now()->addHours(1));
return $user;
}
}
try {
$user = $entityManager->getRepository(User::class)->find(1);
} catch (\Bankiru\Api\Rpc\RpcException $e) {
Log::error("RPC Error: " . $e->getMessage());
throw new \RuntimeException("Failed to fetch user data.");
}
RpcClient in tests to avoid hitting real APIs.use Bankiru\Api\Rpc\RpcClientInterface;
use Mockery;
$mockClient = Mockery::mock(RpcClientInterface::class);
$mockClient->shouldReceive('invoke')
->andReturn(new \Bankiru\Api\Rpc\Response([['id'
How can I help you explore Laravel packages today?