Search by

damienfern / grpc-symfony-bundle

damienfern

Wire generated protobuf service interfaces to Symfony services and dispatch gRPC/HTTP RPCs to them, with zero manual service registration.

Package info

github.com/damienfern/grpc-symfony-bundle

Language:Go

Type:symfony-bundle

pkg:composer/damienfern/grpc-symfony-bundle

Statistics

Installs: 4

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-09-18 11:38 UTC

This package is auto-updated.

Last update: 2026-09-18 11:39:18 UTC


README

Wires generated protobuf service interfaces to Symfony services, and dispatches gRPC/HTTP RPCs to them, with zero manual service registration. Extracted from a proof-of-concept (grpc-symfony) so any Symfony app exposing gRPC can reuse the same pattern.

What's in here

  • src/GrpcServiceInterface.php — marker interface. Every proto service interface generated by tools/protoc-gen-php-grpc-service extends it.
  • src/GrpcRouter.php — dispatches an RPC (by method name) to the Symfony service implementing it, reading the request's PHP class straight off the handler method's parameter type via reflection.
  • src/GrpcSymfonyBundle.php + src/DependencyInjection/ — registering the bundle auto-tags any class implementing GrpcServiceInterface and builds GrpcRouter's whole RPC-method -> handler dispatch table at container-compile time. Nothing to add to your services.yaml, ever, not even for a new RPC on an existing service.
  • tools/protoc-gen-php-grpc-service/ — a protoc plugin generating one PHP interface per proto service (the official PHP protoc output only emits message classes, never server-side interfaces). Ships prebuilt for linux-amd64 and darwin-arm64 as vendor/bin/protoc-gen-php-grpc-service (see "Usage" below) — no Go toolchain needed on those platforms. Other platforms: build it yourself from this directory (see its Makefile).
  • tools/protoc-gen-go-grpc-bridge/ — a protoc plugin generating, for a Go gRPC server, one struct per proto service that forwards every RPC to a callPHP(ctx, method, req, resp) function you provide (see step 2 in "Usage" below). Ships prebuilt for linux-amd64 and darwin-arm64 as vendor/bin/protoc-gen-go-grpc-bridge, same as the PHP plugin. Only needed if your Go gRPC server calls out to PHP the same way the original POC does (e.g. via frankenphp-grpc); skip it if your Go server is wired some other way.

Usage

  1. Require the bundle and enable it:

    composer require dfernandes/grpc-symfony-bundle
    // config/bundles.php
    return [
        // ...
        GrpcSymfony\GrpcSymfonyBundle::class => ['all' => true],
    ];
  2. Generate a service interface per proto service, pointing protoc at the plugin the bundle already ships in vendor/bin/:

    protoc \
      --plugin=protoc-gen-php-grpc-service=vendor/bin/protoc-gen-php-grpc-service \
      --php_out=proto/php \
      --php-grpc-service_out=proto/php \
      your.proto

    This generates e.g. Helloworld\GreeterServiceInterface, extending \GrpcSymfony\GrpcServiceInterface by default. Pass --php-grpc-service_opt=marker=\Some\Other\Interface if you don't want the bundle's own dispatch table.

    If your Go gRPC server needs a per-service bridge struct forwarding every RPC to PHP, add protoc-gen-go-grpc-bridge to the same invocation — it's prebuilt in vendor/bin/ too:

    protoc \
      --plugin=protoc-gen-php-grpc-service=vendor/bin/protoc-gen-php-grpc-service \
      --plugin=protoc-gen-go-grpc-bridge=vendor/bin/protoc-gen-go-grpc-bridge \
      --php_out=proto/php \
      --php-grpc-service_out=proto/php \
      --go-grpc-bridge_out=<dir> --go-grpc-bridge_opt=package=<pkg> \
      your.proto

    This is only needed if your Go gRPC server calls out to PHP the same way the original POC does (e.g. via frankenphp-grpc); skip it if your Go server is wired some other way. It assumes a callPHP(ctx, method string, req, resp proto.Message) error function exists in the target package — see the original POC's grpc/server.go for a worked example.

  3. Implement the generated interface with an ordinary Symfony service — no tagging, no services.yaml entry:

    final class GreeterHandler implements \Helloworld\GreeterServiceInterface
    {
        public function sayHello(\Helloworld\HelloRequest $request): \Helloworld\HelloReply
        {
            return (new \Helloworld\HelloReply())->setMessage("Hello, {$request->getName()}");
        }
    }
  4. Dispatch a request through GrpcSymfony\GrpcRouter (fetched from the container, e.g. from a gRPC worker entry point, or injected into another service like an HTTP controller):

    $router->route('SayHello', $binaryProtobufPayload);   // raw protobuf wire format
    $router->routeJson('SayHello', $jsonPayload);          // protobuf JSON