You've already forked Php-Template
feat/grpc #25
11
.rr.yaml
11
.rr.yaml
@@ -6,6 +6,17 @@ server:
|
||||
rpc:
|
||||
listen: tcp://127.0.0.1:6001
|
||||
|
||||
grpc:
|
||||
listen: "tcp://0.0.0.0:9001"
|
||||
pool:
|
||||
command: "php grpc-worker.php"
|
||||
num_workers: ${GRPC_WORKERS:-4}
|
||||
debug: ${DEBUG:-false}
|
||||
reflection: ${GRPC_REFLECTION:-true}
|
||||
destroy_timeout: 5s
|
||||
proto:
|
||||
- "protos/example.proto"
|
||||
|
||||
http:
|
||||
pool:
|
||||
allocate_timeout: 5s
|
||||
|
||||
@@ -42,11 +42,14 @@ COPY --from=library /app/vendor /app/vendor
|
||||
|
||||
# Copy the RoadRunner configuration file and source
|
||||
ADD src src/
|
||||
ADD generated generated/
|
||||
ADD protos protos/
|
||||
ADD server.php .
|
||||
ADD .rr.yaml .
|
||||
ADD config.php .
|
||||
|
||||
EXPOSE 9501
|
||||
EXPOSE 9001
|
||||
|
||||
# Entrypoint command to run the RoadRunner server with the specified configuration
|
||||
ENTRYPOINT ["rr", "serve", "-c", ".rr.yaml", "-s"]
|
||||
139
README.md
139
README.md
@@ -2,55 +2,132 @@
|
||||
|
||||

|
||||
|
||||
## Overview
|
||||
|
||||
This is a PHP project template that provides a structured development environment using Docker Compose and Make.
|
||||
It includes tools for code quality, testing, dependency management, and gRPC support.
|
||||
|
||||
## Dev Environment
|
||||
|
||||
### Prerequisites
|
||||
- Docker
|
||||
- Docker Compose
|
||||
This project uses Docker Compose and Make to manage the development environment. The `makefile` provides convenient
|
||||
commands for common development tasks.
|
||||
|
||||
### migrations
|
||||
## Prerequisites
|
||||
|
||||
create a new migration
|
||||
```shell
|
||||
docker run --rm -v $(PWD):/app siteworxpro/migrate:v4.18.3 create -ext sql -dir /app/db/migrations -seq create_users_table
|
||||
- Docker and Docker Compose
|
||||
- Make
|
||||
- protoc (Protocol Buffers compiler) - for gRPC code generation
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
# Install PHP dependencies
|
||||
make composer-install
|
||||
|
||||
# Start the development container
|
||||
make start
|
||||
|
||||
# Run the application server
|
||||
make run
|
||||
```
|
||||
|
||||
```text
|
||||
postgres://siteworxpro:password@localhost:5432/siteworxpro?sslmode=disable
|
||||
## Available Commands
|
||||
|
||||
### Container Management
|
||||
|
||||
- `make start` - Start the development runtime container
|
||||
- `make stop` - Stop and remove all containers
|
||||
- `make restart` - Restart the development container
|
||||
- `make rebuild` - Rebuild containers (use after Dockerfile changes)
|
||||
- `make sh` - Open a shell in the development container
|
||||
- `make ps` - Show running containers
|
||||
|
||||
### Application
|
||||
|
||||
- `make run` - Run the application server (RoadRunner)
|
||||
- `make migrate` - Run database migrations
|
||||
|
||||
### Composer & Dependencies
|
||||
|
||||
- `make composer-install` - Install PHP dependencies
|
||||
- `make composer-update` - Update PHP dependencies
|
||||
- `make composer-require package=vendor/package` - Add a new dependency
|
||||
- `make composer-require-dev package=vendor/package` - Add a new dev dependency
|
||||
|
||||
### Code Quality
|
||||
|
||||
- `make lint` - Run linters (phpcs and phpstan)
|
||||
- `make fmt` - Format code with php-cs-fixer
|
||||
- `make test` - Run the test suite (phpunit)
|
||||
- `make license-check` - Check license headers in source files
|
||||
|
||||
### Debugging & Coverage
|
||||
|
||||
- `make enable-debug` - Enable Xdebug for debugging
|
||||
- `make enable-coverage` - Enable PCOV for code coverage
|
||||
|
||||
### gRPC
|
||||
|
||||
- `make protoc` - Generate PHP gRPC code from `.proto` files
|
||||
|
||||
### CI Workflow
|
||||
|
||||
- `make ci` - Run the full CI pipeline locally (install, license check, lint, test)
|
||||
|
||||
### Help
|
||||
|
||||
- `make help` - Show all available commands with descriptions
|
||||
|
||||
## Common Workflows
|
||||
|
||||
### Starting Development
|
||||
|
||||
```bash
|
||||
make composer-install
|
||||
make start
|
||||
make run
|
||||
```
|
||||
|
||||
```shell
|
||||
docker run --rm -v $(PWD):/app siteworxpro/migrate:v4.18.3 -database "postgres://siteworxpro:password@localhost:5432/siteworxpro?sslmode=disable" -path /app/db/migrations up
|
||||
### Adding a New Package
|
||||
|
||||
```bash
|
||||
make composer-require package=vendor/package-name
|
||||
```
|
||||
|
||||
### Starting the Runtime
|
||||
```shell
|
||||
docker-compose up -d
|
||||
```
|
||||
### Start the server
|
||||
```shell
|
||||
docker exec -it template-dev-runtime-1 rr serve
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
make test
|
||||
```
|
||||
|
||||
You can access the api at `http://localhost:9501/`
|
||||
### Code Quality Check
|
||||
|
||||
### Xdebug
|
||||
|
||||
xdebug needs to be built into the container before it will work
|
||||
```shell
|
||||
docker exec -it php-template-composer-runtime-1 bin/xdebug.sh
|
||||
```bash
|
||||
make lint
|
||||
make fmt
|
||||
```
|
||||
|
||||
### Install the dependencies
|
||||
```shell
|
||||
docker run --rm -v $(PWD):/app siteworxpro/composer install --ignore-platform-reqs
|
||||
### Debugging
|
||||
|
||||
```bash
|
||||
make enable-debug
|
||||
make run
|
||||
```
|
||||
|
||||
### Running all tests
|
||||
```shell
|
||||
docker run --rm -v $(PWD):/app siteworxpro/composer run tests:all
|
||||
```
|
||||
## Notes
|
||||
|
||||
- All commands run inside Docker containers, ensuring a consistent environment
|
||||
- The development runtime uses RoadRunner as the application server
|
||||
- Composer commands run in a separate `composer-runtime` container
|
||||
- Database migrations run in a dedicated `migration-container`
|
||||
|
||||
## Additional Information
|
||||
|
||||
### Accessing Services
|
||||
|
||||
- You can access the api at [https://localhost](https://localhost)
|
||||
- Traefik dashboard is at [https://127.0.0.1/dashboard/](https://127.0.0.1/dashboard/)
|
||||
- the grpc server is at [tcp://localhost:9001](tcp://localhost:9001)
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Siteworxpro\\App\\": "src/",
|
||||
"Siteworxpro\\Tests\\": "tests/"
|
||||
"Siteworxpro\\Tests\\": "tests/",
|
||||
"GRPC\\": "generated/GRPC"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
@@ -25,7 +26,8 @@
|
||||
"react/promise": "^3",
|
||||
"react/async": "^4",
|
||||
"guzzlehttp/guzzle": "^7.10",
|
||||
"zircote/swagger-php": "^5.7"
|
||||
"zircote/swagger-php": "^5.7",
|
||||
"spiral/roadrunner-grpc": "^3.5"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^12.4",
|
||||
|
||||
142
composer.lock
generated
142
composer.lock
generated
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "f12aaf0dae6930c226e719a5705e3f91",
|
||||
"content-hash": "977f74570c671e4d59fd70d5e732c3d2",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/cli",
|
||||
@@ -298,6 +298,65 @@
|
||||
],
|
||||
"time": "2025-08-10T19:31:58+00:00"
|
||||
},
|
||||
{
|
||||
"name": "google/common-protos",
|
||||
"version": "4.12.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/googleapis/common-protos-php.git",
|
||||
"reference": "0127156899af0df2681bd42024c60bd5360d64e3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/googleapis/common-protos-php/zipball/0127156899af0df2681bd42024c60bd5360d64e3",
|
||||
"reference": "0127156899af0df2681bd42024c60bd5360d64e3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"google/protobuf": "^4.31",
|
||||
"php": "^8.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^9.6"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"component": {
|
||||
"id": "common-protos",
|
||||
"path": "CommonProtos",
|
||||
"entry": "README.md",
|
||||
"target": "googleapis/common-protos-php.git"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Google\\Api\\": "src/Api",
|
||||
"Google\\Iam\\": "src/Iam",
|
||||
"Google\\Rpc\\": "src/Rpc",
|
||||
"Google\\Type\\": "src/Type",
|
||||
"Google\\Cloud\\": "src/Cloud",
|
||||
"GPBMetadata\\Google\\Api\\": "metadata/Api",
|
||||
"GPBMetadata\\Google\\Iam\\": "metadata/Iam",
|
||||
"GPBMetadata\\Google\\Rpc\\": "metadata/Rpc",
|
||||
"GPBMetadata\\Google\\Type\\": "metadata/Type",
|
||||
"GPBMetadata\\Google\\Cloud\\": "metadata/Cloud",
|
||||
"GPBMetadata\\Google\\Logging\\": "metadata/Logging"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"Apache-2.0"
|
||||
],
|
||||
"description": "Google API Common Protos for PHP",
|
||||
"homepage": "https://github.com/googleapis/common-protos-php",
|
||||
"keywords": [
|
||||
"google"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/googleapis/common-protos-php/tree/v4.12.4"
|
||||
},
|
||||
"time": "2025-09-20T01:29:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "google/protobuf",
|
||||
"version": "v4.33.1",
|
||||
@@ -2943,6 +3002,87 @@
|
||||
],
|
||||
"time": "2025-11-13T17:24:29+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spiral/roadrunner-grpc",
|
||||
"version": "v3.5.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/roadrunner-php/grpc.git",
|
||||
"reference": "916c061de160d6b2f3efc82dcffac0360d84fab8"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/roadrunner-php/grpc/zipball/916c061de160d6b2f3efc82dcffac0360d84fab8",
|
||||
"reference": "916c061de160d6b2f3efc82dcffac0360d84fab8",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"ext-json": "*",
|
||||
"google/common-protos": "^3.1|^4.0",
|
||||
"google/protobuf": "^3.7 || ^4.0",
|
||||
"php": ">=8.1",
|
||||
"spiral/goridge": "^4.0",
|
||||
"spiral/roadrunner": "^2024.3 || ^2025.1",
|
||||
"spiral/roadrunner-worker": "^3.0",
|
||||
"symfony/polyfill-php83": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"jetbrains/phpstorm-attributes": "^1.0",
|
||||
"mockery/mockery": "^1.4",
|
||||
"phpunit/phpunit": "^10.0",
|
||||
"spiral/code-style": "^2.2",
|
||||
"spiral/dumper": "^3.3",
|
||||
"vimeo/psalm": ">=5.8"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Spiral\\RoadRunner\\GRPC\\": "src"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Anton Titov (wolfy-j)",
|
||||
"email": "wolfy-j@spiralscout.com"
|
||||
},
|
||||
{
|
||||
"name": "Pavel Buchnev (butschster)",
|
||||
"email": "pavel.buchnev@spiralscout.com"
|
||||
},
|
||||
{
|
||||
"name": "Aleksei Gagarin (roxblnfk)",
|
||||
"email": "alexey.gagarin@spiralscout.com"
|
||||
},
|
||||
{
|
||||
"name": "Maksim Smakouz (msmakouz)",
|
||||
"email": "maksim.smakouz@spiralscout.com"
|
||||
},
|
||||
{
|
||||
"name": "RoadRunner Community",
|
||||
"homepage": "https://github.com/spiral/roadrunner/graphs/contributors"
|
||||
}
|
||||
],
|
||||
"description": "High-Performance GRPC server for PHP applications",
|
||||
"homepage": "https://roadrunner.dev/",
|
||||
"support": {
|
||||
"chat": "https://discord.gg/V6EK4he",
|
||||
"docs": "https://docs.roadrunner.dev",
|
||||
"forum": "https://forum.roadrunner.dev/",
|
||||
"issues": "https://github.com/roadrunner-server/roadrunner/issues",
|
||||
"source": "https://github.com/roadrunner-php/grpc/tree/v3.5.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
"url": "https://github.com/sponsors/roadrunner-server",
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2025-05-18T13:54:33+00:00"
|
||||
},
|
||||
{
|
||||
"name": "spiral/roadrunner-http",
|
||||
"version": "v3.6.0",
|
||||
|
||||
@@ -14,7 +14,6 @@ return [
|
||||
*/
|
||||
'server' => [
|
||||
'port' => Env::get('HTTP_PORT', 9501, 'int'),
|
||||
'dev_mode' => Env::get('DEV_MODE', false, 'bool'),
|
||||
],
|
||||
|
||||
/**
|
||||
|
||||
@@ -5,6 +5,12 @@ volumes:
|
||||
services:
|
||||
|
||||
traefik:
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.http.routers.traefik.entrypoints=web-secure"
|
||||
- "traefik.http.routers.traefik.rule=Host(`127.0.0.1`) && (PathPrefix(`/dashboard`) || PathPrefix(`/api`))"
|
||||
- "traefik.http.routers.traefik.tls=true"
|
||||
- "traefik.http.routers.traefik.service=api@internal"
|
||||
image: traefik:latest
|
||||
container_name: traefik
|
||||
healthcheck:
|
||||
@@ -15,15 +21,18 @@ services:
|
||||
ports:
|
||||
- "80:80"
|
||||
- "443:443"
|
||||
- "9001:9001"
|
||||
volumes:
|
||||
- "/var/run/docker.sock:/var/run/docker.sock"
|
||||
restart: always
|
||||
command:
|
||||
- "--providers.docker=true"
|
||||
- "--api.insecure=true"
|
||||
- "--ping"
|
||||
- "--providers.docker.exposedByDefault=false"
|
||||
- "--entrypoints.web.address=:80"
|
||||
- "--entrypoints.web-secure.address=:443"
|
||||
- "--entrypoints.grpc.address=:9001"
|
||||
- "--accesslog=true"
|
||||
- "--entrypoints.web.http.redirections.entryPoint.to=web-secure"
|
||||
- "--entrypoints.web.http.redirections.entryPoint.scheme=https"
|
||||
@@ -79,6 +88,13 @@ services:
|
||||
- "traefik.http.services.api.loadbalancer.healthcheck.path=/healthz"
|
||||
- "traefik.http.services.api.loadbalancer.healthcheck.interval=5s"
|
||||
- "traefik.http.services.api.loadbalancer.healthcheck.timeout=60s"
|
||||
- "traefik.tcp.services.api.loadbalancer.server.port=9001"
|
||||
- "traefik.http.services.api.loadbalancer.server.port=9501"
|
||||
- "traefik.tcp.routers.grpc.entrypoints=grpc"
|
||||
- "traefik.tcp.routers.grpc.rule=HostSNI(`localhost`) || HostSNI(`127.0.0.1`)"
|
||||
- "traefik.tcp.routers.grpc.tls=true"
|
||||
- "traefik.tcp.routers.grpc.service=api"
|
||||
container_name: dev-runtime
|
||||
volumes:
|
||||
- .:/app
|
||||
build:
|
||||
@@ -103,6 +119,7 @@ services:
|
||||
QUEUE_BROKER: redis
|
||||
PHP_IDE_CONFIG: serverName=localhost
|
||||
WORKERS: 1
|
||||
GRPC_WORKERS: 1
|
||||
DEBUG: 1
|
||||
REDIS_HOST: redis
|
||||
DB_HOST: postgres
|
||||
|
||||
25
generated/GRPC/GPBMetadata/Example.php
Normal file
25
generated/GRPC/GPBMetadata/Example.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# NO CHECKED-IN PROTOBUF GENCODE
|
||||
# source: protos/example.proto
|
||||
|
||||
namespace GRPC\GPBMetadata;
|
||||
|
||||
class Example
|
||||
{
|
||||
public static $is_initialized = false;
|
||||
|
||||
public static function initOnce() {
|
||||
$pool = \Google\Protobuf\Internal\DescriptorPool::getGeneratedPool();
|
||||
|
||||
if (static::$is_initialized == true) {
|
||||
return;
|
||||
}
|
||||
$pool->internalAddGeneratedFile(
|
||||
"\x0A\xE5\x01\x0A\x14protos/example.proto\x12\x0Ahelloworld\"\x1C\x0A\x0CHelloRequest\x12\x0C\x0A\x04name\x18\x01 \x01(\x09\"\x1D\x0A\x0AHelloReply\x12\x0F\x0A\x07message\x18\x01 \x01(\x092I\x0A\x07Greeter\x12>\x0A\x08SayHello\x12\x18.helloworld.HelloRequest\x1A\x16.helloworld.HelloReply\"\x00B1Z\x0Dproto/greeter\xCA\x02\x0CGRPC\\Greeter\xE2\x02\x10GRPC\\GPBMetadatab\x06proto3"
|
||||
, true);
|
||||
|
||||
static::$is_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
22
generated/GRPC/Greeter/GreeterInterface.php
Normal file
22
generated/GRPC/Greeter/GreeterInterface.php
Normal file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler (roadrunner-server/grpc). DO NOT EDIT!
|
||||
# source: protos/example.proto
|
||||
|
||||
namespace GRPC\Greeter;
|
||||
|
||||
use Spiral\RoadRunner\GRPC;
|
||||
|
||||
interface GreeterInterface extends GRPC\ServiceInterface
|
||||
{
|
||||
// GRPC specific service name.
|
||||
public const NAME = "helloworld.Greeter";
|
||||
|
||||
/**
|
||||
* @param GRPC\ContextInterface $ctx
|
||||
* @param HelloRequest $in
|
||||
* @return HelloReply
|
||||
*
|
||||
* @throws GRPC\Exception\InvokeException
|
||||
*/
|
||||
public function SayHello(GRPC\ContextInterface $ctx, HelloRequest $in): HelloReply;
|
||||
}
|
||||
61
generated/GRPC/Greeter/HelloReply.php
Normal file
61
generated/GRPC/Greeter/HelloReply.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# NO CHECKED-IN PROTOBUF GENCODE
|
||||
# source: protos/example.proto
|
||||
|
||||
namespace GRPC\Greeter;
|
||||
|
||||
use Google\Protobuf\Internal\GPBType;
|
||||
use Google\Protobuf\Internal\GPBUtil;
|
||||
use Google\Protobuf\RepeatedField;
|
||||
|
||||
/**
|
||||
* The response message containing the greetings
|
||||
*
|
||||
* Generated from protobuf message <code>helloworld.HelloReply</code>
|
||||
*/
|
||||
class HelloReply extends \Google\Protobuf\Internal\Message
|
||||
{
|
||||
/**
|
||||
* Generated from protobuf field <code>string message = 1;</code>
|
||||
*/
|
||||
protected $message = '';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $data {
|
||||
* Optional. Data for populating the Message object.
|
||||
*
|
||||
* @type string $message
|
||||
* }
|
||||
*/
|
||||
public function __construct($data = NULL) {
|
||||
\GRPC\GPBMetadata\Example::initOnce();
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>string message = 1;</code>
|
||||
* @return string
|
||||
*/
|
||||
public function getMessage()
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>string message = 1;</code>
|
||||
* @param string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setMessage($var)
|
||||
{
|
||||
GPBUtil::checkString($var, True);
|
||||
$this->message = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
61
generated/GRPC/Greeter/HelloRequest.php
Normal file
61
generated/GRPC/Greeter/HelloRequest.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||
# NO CHECKED-IN PROTOBUF GENCODE
|
||||
# source: protos/example.proto
|
||||
|
||||
namespace GRPC\Greeter;
|
||||
|
||||
use Google\Protobuf\Internal\GPBType;
|
||||
use Google\Protobuf\Internal\GPBUtil;
|
||||
use Google\Protobuf\RepeatedField;
|
||||
|
||||
/**
|
||||
* The request message containing the user's name.
|
||||
*
|
||||
* Generated from protobuf message <code>helloworld.HelloRequest</code>
|
||||
*/
|
||||
class HelloRequest extends \Google\Protobuf\Internal\Message
|
||||
{
|
||||
/**
|
||||
* Generated from protobuf field <code>string name = 1;</code>
|
||||
*/
|
||||
protected $name = '';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $data {
|
||||
* Optional. Data for populating the Message object.
|
||||
*
|
||||
* @type string $name
|
||||
* }
|
||||
*/
|
||||
public function __construct($data = NULL) {
|
||||
\GRPC\GPBMetadata\Example::initOnce();
|
||||
parent::__construct($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>string name = 1;</code>
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generated from protobuf field <code>string name = 1;</code>
|
||||
* @param string $var
|
||||
* @return $this
|
||||
*/
|
||||
public function setName($var)
|
||||
{
|
||||
GPBUtil::checkString($var, True);
|
||||
$this->name = $var;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
3
generated/README.md
Normal file
3
generated/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
### Note to Developers
|
||||
Only generated files are allowed in this directory.
|
||||
Please do not add any other files here manually.
|
||||
14
grpc-worker.php
Normal file
14
grpc-worker.php
Normal file
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
use Siteworxpro\App\Grpc;
|
||||
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
try {
|
||||
$server = new Grpc();
|
||||
exit($server->start());
|
||||
} catch (\Exception $e) {
|
||||
echo $e->getMessage();
|
||||
|
||||
exit(1);
|
||||
}
|
||||
159
makefile
Normal file
159
makefile
Normal file
@@ -0,0 +1,159 @@
|
||||
# Makefile (enhanced)
|
||||
SHELL := /bin/sh
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
# Reusable vars
|
||||
DOCKER := docker compose
|
||||
COMPOSER_RUNTIME := composer-runtime
|
||||
DEV_RUNTIME := dev-runtime
|
||||
MIGRATION_CONTAINER := migration-container
|
||||
|
||||
PROTOC_GEN_DIR := ./protoc-gen-php-grpc-2025.1.5-darwin-arm64
|
||||
PROTOC_GEN := $(PROTOC_GEN_DIR)/protoc-gen-php-grpc
|
||||
PROTOC_URL := https://github.com/roadrunner-server/roadrunner/releases/download/v2025.1.5/protoc-gen-php-grpc-2025.1.5-darwin-arm64.tar.gz
|
||||
|
||||
COMPOSER := $(DOCKER) exec $(COMPOSER_RUNTIME) sh -c
|
||||
DEV := $(DOCKER) exec $(DEV_RUNTIME) sh -c
|
||||
|
||||
# Colors
|
||||
GREEN := \033[32m
|
||||
YELLOW := \033[33m
|
||||
RESET := \033[0m
|
||||
|
||||
# Fancy emoji
|
||||
SPARK := ✨
|
||||
ROCKET := 🚀
|
||||
WARN := ⚠️
|
||||
MAGNIFY := 🔍
|
||||
BUG := 🐞
|
||||
COMPOSE := 🐳
|
||||
TRASH := 🧹
|
||||
PROTO := 🧩
|
||||
CHECK := ✅
|
||||
CROSS := ❌
|
||||
|
||||
# Align width for help display
|
||||
HELP_COL_WIDTH := 26
|
||||
|
||||
# Help: auto-generate from targets with "##" comments
|
||||
help: ## Show this help
|
||||
@echo "$(SPARK) Available commands:"
|
||||
@awk -F':|##' '/^[a-zA-Z0-9._-]+:.*##/ {printf " %-$(HELP_COL_WIDTH)s - %s\n", $$1, $$3}' $(MAKEFILE_LIST) | sort
|
||||
|
||||
start: ## Start the development runtime container
|
||||
@printf "$(GREEN)$(ROCKET) Starting $(DEV_RUNTIME)$(RESET)\n"
|
||||
$(DOCKER) up $(DEV_RUNTIME) -d --no-recreate
|
||||
|
||||
sh: ## Open a shell in the development runtime container
|
||||
@$(MAKE) start
|
||||
$(DOCKER) exec $(DEV_RUNTIME) sh
|
||||
|
||||
run: ## Run the application server in the development runtime container
|
||||
@$(MAKE) start
|
||||
$(DEV) "rr serve"
|
||||
|
||||
stop: ## Stop and remove the development runtime container
|
||||
@printf "$(YELLOW)$(WARN) Stopping all containers$(RESET)\n"
|
||||
$(DOCKER) down
|
||||
|
||||
restart: ## Restart dev container (stop + start)
|
||||
@$(MAKE) stop
|
||||
@$(MAKE) start
|
||||
|
||||
rebuild: ## Rebuild containers (useful after Dockerfile changes)
|
||||
@printf "$(YELLOW)$(SPARK) Rebuilding containers$(RESET)\n"
|
||||
@$(MAKE) stop
|
||||
@printf "$(YELLOW)$(TRASH) Deleting all Docker resources$(RESET)\n"
|
||||
docker system prune --all --volumes --force
|
||||
@$(MAKE) start
|
||||
|
||||
ps: ## Show docker compose ps
|
||||
$(DOCKER) ps
|
||||
|
||||
migrate: ## Run database migrations in the migration container
|
||||
$(DOCKER) up $(MIGRATION_CONTAINER)
|
||||
|
||||
# Composer helpers
|
||||
composer-install: ## Install PHP dependencies in the composer runtime container
|
||||
@printf "$(COMPOSE) $(GREEN)Installing PHP dependencies in $(COMPOSER_RUNTIME)$(RESET)\n"
|
||||
@$(DOCKER) up $(COMPOSER_RUNTIME) -d --no-recreate
|
||||
$(COMPOSER) "composer install --no-interaction --prefer-dist --optimize-autoloader --ignore-platform-reqs"
|
||||
|
||||
composer-require: ## Require a PHP package in the composer runtime container (usage: make composer-require package=vendor/package)
|
||||
ifndef package
|
||||
$(error package variable is required: make composer-require package=vendor/package)
|
||||
endif
|
||||
@printf "$(COMPOSE) $(MAGNIFY) Requiring package $(package) in $(COMPOSER_RUNTIME)$(RESET)\n"
|
||||
@$(DOCKER) up $(COMPOSER_RUNTIME) -d --no-recreate
|
||||
$(COMPOSER) "composer require $(package) --ignore-platform-reqs"
|
||||
|
||||
composer-require-dev: ## Require a PHP package as dev in the composer runtime container (usage: make composer-require-dev package=vendor/package)
|
||||
ifndef package
|
||||
$(error package variable is required: make composer-require-dev package=vendor/package)
|
||||
endif
|
||||
@printf "$(COMPOSE) $(MAGNIFY) Requiring dev package $(package) in $(COMPOSER_RUNTIME)$(RESET)\n"
|
||||
@$(DOCKER) up $(COMPOSER_RUNTIME) -d --no-recreate
|
||||
$(COMPOSER) "composer require --dev $(package) --ignore-platform-reqs"
|
||||
|
||||
composer-update: ## Update PHP dependencies in the composer runtime container
|
||||
@printf "$(COMPOSE) $(MAGNIFY) Updating PHP dependencies$(RESET)\n"
|
||||
@$(DOCKER) up $(COMPOSER_RUNTIME) -d --no-recreate
|
||||
$(COMPOSER) "composer update --no-interaction --prefer-dist --optimize-autoloader --ignore-platform-reqs"
|
||||
|
||||
enable-debug: ## Enable Xdebug in the development runtime container
|
||||
@$(DOCKER) up $(DEV_RUNTIME) -d --no-recreate
|
||||
@printf "$(GREEN)$(BUG) Enabling Xdebug in $(DEV_RUNTIME)$(RESET)\n"
|
||||
$(DEV) "bin/xdebug.sh"
|
||||
|
||||
enable-coverage: ## Enable PCOV code coverage in the composer runtime container
|
||||
@printf "$(GREEN)$(MAGNIFY) Enabling PCOV in $(COMPOSER_RUNTIME)$(RESET)\n"
|
||||
@$(DOCKER) up $(COMPOSER_RUNTIME) -d --no-recreate
|
||||
$(COMPOSER) "bin/pcov.sh"
|
||||
|
||||
protoc: ## Generate PHP gRPC code from .proto files
|
||||
@printf "$(PROTO) $(GREEN)Setting up protoc-gen-php-grpc plugin$(RESET)\n"
|
||||
@curl -LOs $(PROTOC_URL)
|
||||
@tar -xzf protoc-gen-php-grpc-2025.1.5-darwin-arm64.tar.gz
|
||||
@printf "$(PROTO) $(GREEN)Generating PHP gRPC code from .proto files$(RESET)\n"
|
||||
@protoc --plugin=./protoc-gen-php-grpc-2025.1.5-darwin-arm64/protoc-gen-php-grpc \
|
||||
--php_out=./generated \
|
||||
--php-grpc_out=./generated \
|
||||
protos/example.proto
|
||||
@printf "$(TRASH) $(GREEN)Cleaning up protoc-gen-php-grpc plugin files$(RESET)\n"
|
||||
@rm -rf $(PROTOC_GEN_DIR) protoc-gen-php-grpc-2025.1.5-darwin-arm64.tar.gz
|
||||
|
||||
license-check: ## Check license headers in source files
|
||||
@printf "$(MAGNIFY) $(GREEN)Checking license headers$(RESET)\n"
|
||||
@$(DOCKER) up $(COMPOSER_RUNTIME) -d --no-recreate
|
||||
$(COMPOSER) "composer run-script tests:license || true"
|
||||
|
||||
# Developer tasks
|
||||
lint: ## Run linting (phpcs/phpstan) in composer runtime
|
||||
@printf "$(MAGNIFY) $(GREEN)Running linters$(RESET)\n"
|
||||
@$(DOCKER) up $(COMPOSER_RUNTIME) -d --no-recreate
|
||||
$(COMPOSER) "composer run-script tests:lint || true"
|
||||
$(COMPOSER) "composer run-script tests:phpstan || true"
|
||||
|
||||
fmt: ## Format code (php-cs-fixer)
|
||||
@printf "$(MAGNIFY) $(GREEN)Formatting code$(RESET)\n"
|
||||
@$(DOCKER) up $(COMPOSER_RUNTIME) -d --no-recreate
|
||||
$(COMPOSER) "composer run-script tests:lint:fix"
|
||||
|
||||
test: ## Run test suite (phpunit)
|
||||
@printf "$(CHECK) $(GREEN)Running unit tests$(RESET)\n"
|
||||
@$(DOCKER) up $(COMPOSER_RUNTIME) -d
|
||||
$(COMPOSER) "composer run-script tests:unit || true"
|
||||
|
||||
test-coverage: ## Run test suite with coverage report
|
||||
@printf "$(CHECK) $(GREEN)Running unit tests with coverage report$(RESET)\n"
|
||||
@$(DOCKER) up $(COMPOSER_RUNTIME) -d
|
||||
@$(MAKE) enable-coverage
|
||||
$(COMPOSER) "composer run-script tests:unit:coverage || true"
|
||||
|
||||
# Convenience aliases
|
||||
dev: run ## Alias for start
|
||||
ci: composer-install license-check lint test ## CI-like local flow
|
||||
down: stop ## Alias for stop
|
||||
up: start ## Alias for start
|
||||
|
||||
.PONY: help start sh run stop restart rebuild ps migrate composer-install composer-require composer-require-dev composer-update enable-debug enable-coverage protoc license-check lint fmt test test-coverage dev ci down up
|
||||
23
protos/example.proto
Normal file
23
protos/example.proto
Normal file
@@ -0,0 +1,23 @@
|
||||
syntax = "proto3";
|
||||
|
||||
option go_package = "proto/greeter";
|
||||
option php_namespace = "GRPC\\Greeter";
|
||||
option php_metadata_namespace = "GRPC\\GPBMetadata";
|
||||
|
||||
package helloworld;
|
||||
|
||||
// The greeting service definition.
|
||||
service Greeter {
|
||||
// Sends a greeting
|
||||
rpc SayHello (HelloRequest) returns (HelloReply) {}
|
||||
}
|
||||
|
||||
// The request message containing the user's name.
|
||||
message HelloRequest {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
// The response message containing the greetings
|
||||
message HelloReply {
|
||||
string message = 1;
|
||||
}
|
||||
@@ -5,10 +5,7 @@ use Siteworxpro\App\Api;
|
||||
require __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
try {
|
||||
// Instantiate the ExternalServer class
|
||||
$server = new Api();
|
||||
|
||||
// Start the server
|
||||
$server->startServer();
|
||||
} catch (JsonException $e) {
|
||||
echo $e->getMessage();
|
||||
|
||||
47
src/Grpc.php
Normal file
47
src/Grpc.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Siteworxpro\App;
|
||||
|
||||
use GRPC\Greeter\GreeterInterface;
|
||||
use Siteworxpro\App\GrpcHandlers\GreeterHandler;
|
||||
use Siteworxpro\App\Services\Facades\Config;
|
||||
use Spiral\RoadRunner\GRPC\Invoker;
|
||||
use Spiral\RoadRunner\GRPC\Server;
|
||||
use Spiral\RoadRunner\Worker;
|
||||
|
||||
/**
|
||||
* Class Grpc
|
||||
*
|
||||
* starts a gRPC server using RoadRunner
|
||||
*
|
||||
* @package Siteworxpro\App
|
||||
*/
|
||||
class Grpc
|
||||
{
|
||||
/**
|
||||
* @throws \ReflectionException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
Kernel::boot();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starts the gRPC server
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function start(): int
|
||||
{
|
||||
$server = new Server(new Invoker(), [
|
||||
'debug' => Config::get('app.dev_mode'),
|
||||
]);
|
||||
|
||||
$server->registerService(GreeterInterface::class, new GreeterHandler());
|
||||
$server->serve(Worker::create());
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
21
src/GrpcHandlers/GreeterHandler.php
Normal file
21
src/GrpcHandlers/GreeterHandler.php
Normal file
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Siteworxpro\App\GrpcHandlers;
|
||||
|
||||
use GRPC\Greeter\GreeterInterface;
|
||||
use GRPC\Greeter\HelloReply;
|
||||
use GRPC\Greeter\HelloRequest;
|
||||
use Spiral\RoadRunner\GRPC;
|
||||
|
||||
class GreeterHandler implements GreeterInterface
|
||||
{
|
||||
public function SayHello(GRPC\ContextInterface $ctx, HelloRequest $in): HelloReply // phpcs:ignore
|
||||
{
|
||||
$reply = new HelloReply();
|
||||
$reply->setMessage('Hello ' . $in->getName());
|
||||
|
||||
return $reply;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user