Skip to content

Commit

Permalink
Adding the ability to generate TCP service and Centrifugo handler via…
Browse files Browse the repository at this point in the history
… Scaffolder (#80)

* Add the ability to generate TCP service and Centrifugo handler

* Fix CS, fix Psalm

* Improve tests

* PHPUnit 10

* Fix CS
  • Loading branch information
msmakouz authored May 29, 2023
1 parent dbb7f42 commit 5014fc6
Show file tree
Hide file tree
Showing 22 changed files with 488 additions and 55 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ composer.phar
Thumbs.db

# Other
.phpunit.result.cache
.phpunit.cache
build
.php_cs.cache
clover.xml
.env
Expand Down
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ protected const LOAD = [
RoadRunnerBridge\TcpBootloader::class, // Optional, if it needs to work with TCP plugin
RoadRunnerBridge\MetricsBootloader::class, // Optional, if it needs to work with metrics plugin
RoadRunnerBridge\LoggerBootloader::class, // Optional, if it needs to work with app-logger plugin
RoadRunnerBridge\ScaffolderBootloader::class, // Optional, to generate Centrifugo handlers and TCP services via Scaffolder
RoadRunnerBridge\CommandBootloader::class,
// ...
];
Expand Down Expand Up @@ -166,6 +167,19 @@ class TestService implements ServiceInterface
}
```

The service can be generated using the **Scaffolder** component. Make sure that bootloader
`Spiral\RoadRunnerBridge\Bootloader\ScaffolderBootloader` is added in your application and run:

```bash
php app.php create:tcp-service Test
```

This will generate service **TestService** in the folder **Endpoint/Tcp/Service/TestService.php**.

> **Note**
> Namespace (and generation path) can be configured.
> Read more about [Scaffolder component](https://spiral.dev/docs/basics-scaffolding).

----

> **Note**
Expand Down
6 changes: 4 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,12 @@
"spiral/roadrunner-metrics": "^3.0",
"roadrunner-php/app-logger": "^1.0",
"spiral/framework": "^3.7",
"spiral/serializer": "^3.7"
"spiral/serializer": "^3.7",
"spiral/scaffolder": "^3.7"
},
"require-dev": {
"spiral/testing": "^2.2",
"spiral/testing": "^2.3",
"phpunit/phpunit": "^10.1",
"vimeo/psalm": "^5.0",
"spiral/nyholm-bridge": "^1.2"
},
Expand Down
33 changes: 25 additions & 8 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" bootstrap="vendor/autoload.php" backupGlobals="false"
backupStaticAttributes="false" colors="true" verbose="false" convertErrorsToExceptions="true"
convertNoticesToExceptions="true" convertWarningsToExceptions="true" processIsolation="false"
stopOnFailure="false" stopOnError="false" stderr="false"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
bootstrap="vendor/autoload.php"
backupGlobals="false"
colors="true"
processIsolation="false"
stopOnFailure="false"
stopOnError="false"
stderr="false"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
cacheDirectory=".phpunit.cache"
backupStaticProperties="false"
>
<coverage>
<include>
<directory>src</directory>
</include>
<report>
<html outputDirectory="build/coverage"/>
<text outputFile="build/coverage.txt"/>
<clover outputFile="build/logs/clover.xml"/>
</report>
</coverage>
<logging>
<junit outputFile="build/report.junit.xml"/>
</logging>
<testsuites>
<testsuite name="Test Suite">
<directory>tests/src</directory>
Expand All @@ -18,4 +30,9 @@
<ini name="error_reporting" value="-1"/>
<ini name="memory_limit" value="-1"/>
</php>
<source>
<include>
<directory>src</directory>
</include>
</source>
</phpunit>
61 changes: 61 additions & 0 deletions src/Bootloader/ScaffolderBootloader.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?php

declare(strict_types=1);

namespace Spiral\RoadRunnerBridge\Bootloader;

use Psr\Container\ContainerInterface;
use RoadRunner\Centrifugo\CentrifugoApiInterface;
use Spiral\Boot\Bootloader\Bootloader;
use Spiral\Console\Bootloader\ConsoleBootloader;
use Spiral\RoadRunnerBridge\Console\Command\Scaffolder\CentrifugoHandlerCommand;
use Spiral\RoadRunnerBridge\Console\Command\Scaffolder\TcpServiceCommand;
use Spiral\RoadRunnerBridge\Scaffolder\Declaration\CentrifugoHandlerDeclaration;
use Spiral\RoadRunnerBridge\Scaffolder\Declaration\TcpServiceDeclaration;
use Spiral\RoadRunnerBridge\Tcp\Server;
use Spiral\Scaffolder\Bootloader\ScaffolderBootloader as BaseScaffolderBootloader;

final class ScaffolderBootloader extends Bootloader
{
public const DEPENDENCIES = [
ConsoleBootloader::class,
BaseScaffolderBootloader::class,
];

public function __construct(
private readonly ContainerInterface $container
) {
}

public function init(BaseScaffolderBootloader $scaffolder, ConsoleBootloader $console): void
{
$this->configureCommands($console);
$this->configureDeclarations($scaffolder);
}

private function configureCommands(ConsoleBootloader $console): void
{
if ($this->container->has(CentrifugoApiInterface::class)) {
$console->addCommand(CentrifugoHandlerCommand::class);
}

if ($this->container->has(Server::class)) {
$console->addCommand(TcpServiceCommand::class);
}
}

private function configureDeclarations(BaseScaffolderBootloader $scaffolder): void
{
$scaffolder->addDeclaration(CentrifugoHandlerDeclaration::TYPE, [
'namespace' => 'Endpoint\\Centrifugo\\Handler',
'postfix' => 'Handler',
'class' => CentrifugoHandlerDeclaration::class,
]);

$scaffolder->addDeclaration(TcpServiceDeclaration::TYPE, [
'namespace' => 'Endpoint\\Tcp\\Service',
'postfix' => 'Service',
'class' => TcpServiceDeclaration::class,
]);
}
}
35 changes: 35 additions & 0 deletions src/Console/Command/Scaffolder/CentrifugoHandlerCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace Spiral\RoadRunnerBridge\Console\Command\Scaffolder;

use Spiral\Console\Attribute\Argument;
use Spiral\Console\Attribute\AsCommand;
use Spiral\Console\Attribute\Option;
use Spiral\Console\Attribute\Question;
use Spiral\RoadRunnerBridge\Scaffolder\Declaration\CentrifugoHandlerDeclaration;
use Spiral\Scaffolder\Command\AbstractCommand;

#[AsCommand(name: 'create:centrifugo-handler', description: 'Create Centrifugo handler declaration')]
final class CentrifugoHandlerCommand extends AbstractCommand
{
#[Argument(description: 'Centrifugo handler name')]
#[Question(question: 'What would you like to name the Centrifugo handler?')]
private string $name;

#[Option(shortcut: 'c', description: 'Optional comment to add as class header')]
private ?string $comment = null;

#[Option(description: 'Optional, specify a custom namespace')]
private ?string $namespace = null;

public function perform(): int
{
$declaration = $this->createDeclaration(CentrifugoHandlerDeclaration::class);

$this->writeDeclaration($declaration);

return self::SUCCESS;
}
}
35 changes: 35 additions & 0 deletions src/Console/Command/Scaffolder/TcpServiceCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace Spiral\RoadRunnerBridge\Console\Command\Scaffolder;

use Spiral\Console\Attribute\Argument;
use Spiral\Console\Attribute\AsCommand;
use Spiral\Console\Attribute\Option;
use Spiral\Console\Attribute\Question;
use Spiral\RoadRunnerBridge\Scaffolder\Declaration\TcpServiceDeclaration;
use Spiral\Scaffolder\Command\AbstractCommand;

#[AsCommand(name: 'create:tcp-service', description: 'Create TCP service declaration')]
final class TcpServiceCommand extends AbstractCommand
{
#[Argument(description: 'TCP service name')]
#[Question(question: 'What would you like to name the TCP service?')]
private string $name;

#[Option(shortcut: 'c', description: 'Optional comment to add as class header')]
private ?string $comment = null;

#[Option(description: 'Optional, specify a custom namespace')]
private ?string $namespace = null;

public function perform(): int
{
$declaration = $this->createDeclaration(TcpServiceDeclaration::class);

$this->writeDeclaration($declaration);

return self::SUCCESS;
}
}
30 changes: 30 additions & 0 deletions src/Scaffolder/Declaration/CentrifugoHandlerDeclaration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

declare(strict_types=1);

namespace Spiral\RoadRunnerBridge\Scaffolder\Declaration;

use RoadRunner\Centrifugo\CentrifugoApiInterface;
use Spiral\Scaffolder\Declaration\AbstractDeclaration;

class CentrifugoHandlerDeclaration extends AbstractDeclaration
{
public const TYPE = 'centrifugo-handler';

public function declare(): void
{
$this->namespace->addUse(CentrifugoApiInterface::class);

$this->class->setFinal();

$this->class->addMethod('__construct')
->setPublic()
->addPromotedParameter('api')
->setPrivate()
->setReadOnly()
->setType(CentrifugoApiInterface::class)
;

$this->class->addMethod('handle')->setPublic()->setReturnType('void');
}
}
35 changes: 35 additions & 0 deletions src/Scaffolder/Declaration/TcpServiceDeclaration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?php

declare(strict_types=1);

namespace Spiral\RoadRunnerBridge\Scaffolder\Declaration;

use Spiral\RoadRunner\Tcp\Request;
use Spiral\RoadRunnerBridge\Tcp\Response\RespondMessage;
use Spiral\RoadRunnerBridge\Tcp\Response\ResponseInterface;
use Spiral\RoadRunnerBridge\Tcp\Service\ServiceInterface;
use Spiral\Scaffolder\Declaration\AbstractDeclaration;

class TcpServiceDeclaration extends AbstractDeclaration
{
public const TYPE = 'tcp-service';

public function declare(): void
{
$this->namespace->addUse(ServiceInterface::class);
$this->namespace->addUse(Request::class);
$this->namespace->addUse(RespondMessage::class);
$this->namespace->addUse(ResponseInterface::class);

$this->class->addImplement(ServiceInterface::class);
$this->class->setFinal();

$this->class->addMethod('handle')
->setPublic()
->addBody("return new RespondMessage('some message', true);")
->setReturnType(ResponseInterface::class)
->addParameter('request')
->setType(Request::class)
;
}
}
2 changes: 1 addition & 1 deletion tests/app/GRPC/Generator/Bootloader/ExpectedBootloader.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
class ServiceBootloader extends Bootloader
{
public function __construct(
public ConfiguratorInterface $config,
private readonly ConfiguratorInterface $config,
) {
}

Expand Down
2 changes: 1 addition & 1 deletion tests/app/GRPC/Generator/ExpectedServiceClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
class UsersServiceClient implements UsersServiceInterface
{
public function __construct(
public InterceptableCore $core,
private readonly InterceptableCore $core,
) {
}

Expand Down
36 changes: 36 additions & 0 deletions tests/src/Bootloader/ScaffolderBootloaderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

declare(strict_types=1);

namespace Spiral\Tests\Bootloader;

use Spiral\RoadRunnerBridge\Scaffolder\Declaration\CentrifugoHandlerDeclaration;
use Spiral\RoadRunnerBridge\Scaffolder\Declaration\TcpServiceDeclaration;
use Spiral\Scaffolder\Config\ScaffolderConfig;
use Spiral\Tests\TestCase;

final class ScaffolderBootloaderTest extends TestCase
{
public function testCommandsShouldBeRegistered(): void
{
$this->assertCommandRegistered('create:centrifugo-handler');
$this->assertCommandRegistered('create:tcp-service');
}

public function testDeclarationsShouldBeRegistered(): void
{
$config = $this->getConfig(ScaffolderConfig::CONFIG);

$this->assertSame([
'namespace' => 'Endpoint\\Centrifugo\\Handler',
'postfix' => 'Handler',
'class' => CentrifugoHandlerDeclaration::class,
], $config['defaults']['declarations'][CentrifugoHandlerDeclaration::TYPE]);

$this->assertSame([
'namespace' => 'Endpoint\\Tcp\\Service',
'postfix' => 'Service',
'class' => TcpServiceDeclaration::class,
], $config['defaults']['declarations'][TcpServiceDeclaration::TYPE]);
}
}
Loading

0 comments on commit 5014fc6

Please sign in to comment.