PHP code example of roadrunner-php / laravel-bridge
1. Go to this page and download the library: Download roadrunner-php/laravel-bridge 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/ */
return [
// ... other configuration
'grpc' => [
'services' => [
\App\GRPC\EchoServiceInterface::class => \App\GRPC\EchoService::class,
// Service with specific interceptors
\App\GRPC\UserServiceInterface::class => [
'service' => \App\GRPC\UserService::class,
'interceptors' => [
\App\GRPC\Interceptors\ValidationInterceptor::class,
\App\GRPC\Interceptors\CacheInterceptor::class,
],
],
]
],
];
namespace App\GRPC\Interceptors;
use Spiral\Interceptors\Context\CallContextInterface;
use Spiral\Interceptors\HandlerInterface;
use Spiral\Interceptors\InterceptorInterface;
class LoggingInterceptor implements InterceptorInterface
{
public function intercept(CallContextInterface $context, HandlerInterface $handler): mixed
{
$method = implode('.', $context->getTarget()->getPath());
\Log::info("gRPC call: {$method}");
$response = $handler->handle($context);
\Log::info("gRPC response: {$method}");
return $response;
}
}
return [
// ... other configuration
'grpc' => [
'services' => [
// Simple service configuration
\App\GRPC\EchoServiceInterface::class => \App\GRPC\EchoService::class,
// Service with specific interceptors
\App\GRPC\UserServiceInterface::class => [
'service' => \App\GRPC\UserService::class,
'interceptors' => [
\App\GRPC\Interceptors\ValidationInterceptor::class,
\App\GRPC\Interceptors\CacheInterceptor::class,
],
],
],
// Global interceptors - applied to all services
'interceptors' => [
\App\GRPC\Interceptors\LoggingInterceptor::class,
\App\GRPC\Interceptors\AuthenticationInterceptor::class,
],
],
];
'interceptors' => [
// ... other global interceptors before
\Spiral\RoadRunnerLaravel\Common\Interceptor\AttributesInterceptor::class,
// ... other global interceptors after
],
namespace App\GRPC\Interceptors;
use Spiral\Interceptors\Context\CallContextInterface;
use Spiral\Interceptors\HandlerInterface;
use Spiral\Interceptors\InterceptorInterface;
use Attribute;
#[Attribute(Attribute::TARGET_CLASS | Attribute::TARGET_METHOD)]
class RoleInterceptor implements InterceptorInterface
{
public function __construct(
private readonly string $role,
) {}
public function intercept(CallContextInterface $context, HandlerInterface $handler): mixed
{
// Check user role
if (!$this->checkRole($this->role)) {
throw new \RuntimeException('Access denied');
}
return $handler->handle($context);
}
}
namespace App\GRPC;
use App\GRPC\Interceptors\LoggingInterceptor;
use App\GRPC\Interceptors\AuthInterceptor;
use App\GRPC\Interceptors\RoleInterceptor;
#[LoggingInterceptor]
#[AuthInterceptor]
class UserService implements UserServiceInterface
{
#[RoleInterceptor('admin')]
public function DeleteUser(GRPC\ContextInterface $ctx, DeleteUserRequest $in): DeleteUserResponse
{
// Implementation - will use class-level + method-level interceptors
}
public function GetUser(GRPC\ContextInterface $ctx, GetUserRequest $in): GetUserResponse
{
// Implementation - will use only class-level interceptors
}
}
use Spiral\Grpc\Client\ServiceClientProvider;
use App\Grpc\EchoServiceInterface;
use App\Grpc\EchoRequest;
class GrpcController extends Controller
{
public function callService(ServiceClientProvider $provider)
{
/** @var EchoServiceInterface $client */
$client = $provider->get(EchoServiceInterface::class);
$request = new EchoRequest();
$request->setMessage('Hello from client!');
$response = $client->Echo($request);
return $response->getMessage();
}
}
use Psr\Log\LoggerInterface;
class YourService
{
public function __construct(
private LoggerInterface $logger
) {}
public function doSomething()
{
$this->logger->info('Operation started');
try {
// Your logic here
$this->logger->info('Operation completed');
} catch (\Exception $e) {
$this->logger->error('Operation failed', [
'exception' => $e->getMessage(),
'trace' => $e->getTraceAsString()
]);
}
}
}
// Get logger from container
$logger = app(LoggerInterface::class);
// Or using the alias
$logger = app('roadrunner.logger');
$logger->info('Message', ['context' => 'data']);
namespace App\Workers;
use Spiral\RoadRunnerLaravel\WorkerInterface;
use Spiral\RoadRunnerLaravel\WorkerOptionsInterface;
class CustomWorker implements WorkerInterface
{
public function start(WorkerOptionsInterface $options): void
{
// Your worker implementation goes here
// This method should handle requests from the RoadRunner server
}
}
return [
// ... other configuration options ...
'workers' => [
// Existing workers
Mode::MODE_HTTP => HttpWorker::class,
Mode::MODE_JOBS => QueueWorker::class,
// Your custom worker for a custom or built-in plugin
'custom_plugin' => \App\Workers\CustomWorker::class,
],
];
namespace App\Workers;
use Laravel\Octane\ApplicationFactory;
use RoadRunner\Centrifugo\CentrifugoWorker as RRCentrifugoWorker;
use RoadRunner\Centrifugo\Payload;
use RoadRunner\Centrifugo\Request;
use RoadRunner\Centrifugo\Request\RequestFactory;
use Spiral\RoadRunner\Worker;
use Spiral\RoadRunnerLaravel\WorkerInterface;
use Spiral\RoadRunnerLaravel\WorkerOptionsInterface;
class CentrifugoWorker implements WorkerInterface
{
public function start(WorkerOptionsInterface $options): void
{
$app = (new ApplicationFactory($options->getAppBasePath()))->createApplication();
// Resolve your handlers from the booted Laravel application, e.g. $app->make(...)
$worker = Worker::create();
$centrifugo = new RRCentrifugoWorker($worker, new RequestFactory($worker));
while ($request = $centrifugo->waitRequest()) {
try {
match (true) {
// Handle client connection
$request instanceof Request\Connect => $request->respond(new Payload\ConnectResponse(
user: 'user-id',
)),
// Handle client subscription
$request instanceof Request\Subscribe => $request->respond(new Payload\SubscribeResponse()),
// Handle client publish
$request instanceof Request\Publish => $request->respond(new Payload\PublishResponse()),
default => null,
};
} catch (\Throwable $e) {
$request->error((int) $e->getCode(), $e->getMessage());
}
}
}
}
use Spiral\RoadRunner\Environment\Mode;
return [
'workers' => [
// ... other workers
Mode::MODE_CENTRIFUGE => \App\Workers\CentrifugoWorker::class,
],
];