Skip to content

Commit

Permalink
Add psalm and phpcs
Browse files Browse the repository at this point in the history
  • Loading branch information
vincent4vx committed Jul 2, 2021
1 parent 82badb1 commit e4d4697
Show file tree
Hide file tree
Showing 11 changed files with 119 additions and 62 deletions.
69 changes: 31 additions & 38 deletions .github/workflows/php.yml
Expand Up @@ -45,41 +45,34 @@ jobs:

- name: Run test suite
run: composer run-script tests
#
# analysis:
# name: Analysis
# runs-on: ubuntu-latest
# env:
# ELASTICSEARCH_HOST: "127.0.0.1:9200"
#
# steps:
# - uses: actions/checkout@v2
#
# - name: Set Timezone
# uses: szenius/set-timezone@v1.0
# with:
# timezoneLinux: "Europe/Paris"
#
# - name: Install PHP
# uses: shivammathur/setup-php@v2
# with:
# php-version: 7.4
# extensions: json
# ini-values: date.timezone=Europe/Paris
##
## - name: Install Infection
## run: composer global require infection/infection
#
# - name: Validate composer.json and composer.lock
# run: composer validate --strict
#
# - name: Install dependencies
# run: composer install --prefer-dist --no-progress
#
# - name: Run type coverage
# run: composer run-script psalm

# - name: Run Infection
# run: |
# git fetch --depth=1 origin $GITHUB_BASE_REF
# ~/.composer/vendor/bin/infection --logger-github --git-diff-filter=AM

analysis:
name: Analysis
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Set Timezone
uses: szenius/set-timezone@v1.0
with:
timezoneLinux: "Europe/Paris"

- name: Install PHP
uses: shivammathur/setup-php@v2
with:
php-version: 7.4
extensions: json
ini-values: date.timezone=Europe/Paris

- name: Install MySQL
run: ./.github/run-mysql.sh

- name: Validate composer.json and composer.lock
run: composer validate --strict

- name: Install dependencies
run: composer install --prefer-dist --no-progress

- name: Run type coverage
run: composer run-script psalm
9 changes: 7 additions & 2 deletions composer.json
Expand Up @@ -30,10 +30,15 @@
"symfony/framework-bundle": "~4.0|~5.0",
"symfony/yaml": "~4.0|~5.0",
"symfony/console": "~4.0|~5.0",
"b2pweb/bdf-prime-bundle": "~1.0"
"b2pweb/bdf-prime-bundle": "~1.0",
"vimeo/psalm": "~4.8",
"psalm/plugin-symfony": "dev-master",
"squizlabs/php_codesniffer": "~3.0"
},
"scripts": {
"tests": "phpunit",
"tests-with-coverage": "phpunit --coverage-clover coverage.xml"
"tests-with-coverage": "phpunit --coverage-clover coverage.xml",
"psalm": "psalm --shepherd",
"phpcs": "phpcs --standard=psr12 --tab-width=4 src/"
}
}
15 changes: 15 additions & 0 deletions psalm.xml
@@ -0,0 +1,15 @@
<?xml version="1.0"?>
<psalm
errorLevel="2"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
<projectFiles>
<directory name="src"/>
<ignoreFiles>
<directory name="vendor"/>
</ignoreFiles>
</projectFiles>
<plugins><pluginClass class="Psalm\SymfonyPsalmPlugin\Plugin"/></plugins></psalm>
9 changes: 8 additions & 1 deletion src/Bundle/DependencyInjection/Configuration.php
Expand Up @@ -2,6 +2,7 @@

namespace Bdf\PrimeEvents\Bundle\DependencyInjection;

use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;

Expand All @@ -12,11 +13,17 @@ class Configuration implements ConfigurationInterface
{
/**
* {@inheritdoc}
*
* @psalm-suppress PossiblyNullReference
* @psalm-suppress PossiblyUndefinedMethod
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder('prime_events');
$treeBuilder->getRootNode()
/** @var ArrayNodeDefinition $root */
$root = $treeBuilder->getRootNode();

$root
->useAttributeAsKey('connection')
->arrayPrototype()
->children()
Expand Down
4 changes: 3 additions & 1 deletion src/Bundle/DependencyInjection/PrimeEventsExtension.php
Expand Up @@ -4,6 +4,7 @@

use Bdf\PrimeEvents\Factory\ConsumersFactory;
use Bdf\PrimeEvents\Factory\EntityEventsListenerInterface;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;
Expand All @@ -17,8 +18,9 @@ class PrimeEventsExtension extends Extension
/**
* {@inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container)
public function load(array $configs, ContainerBuilder $container): void
{
/** @var ConfigurationInterface $configuration */
$configuration = $this->getConfiguration($configs, $container);
$config = $this->processConfiguration($configuration, $configs);

Expand Down
5 changes: 3 additions & 2 deletions src/Bundle/PrimeEventsBundle.php
Expand Up @@ -13,13 +13,14 @@
*/
class PrimeEventsBundle extends Bundle
{
public function build(ContainerBuilder $container)
public function build(ContainerBuilder $container): void
{
$container->addCompilerPass(new class implements CompilerPassInterface {
public function process(ContainerBuilder $container)
public function process(ContainerBuilder $container): void
{
$definition = $container->findDefinition(ConsumersFactory::class);

/** @var string $id */
foreach ($container->findTaggedServiceIds('prime.events.listener') as $id => $_) {
$definition->addMethodCall('register', [new Reference($id)]);
}
Expand Down
10 changes: 5 additions & 5 deletions src/Console/ConsumePrimeEvents.php
Expand Up @@ -35,12 +35,12 @@ class ConsumePrimeEvents extends Command
private $running = true;

/**
* @var int
* @var int|null
*/
private $maxMemory = null;

/**
* @var int
* @var int|null
*/
private $limit = null;

Expand All @@ -60,7 +60,7 @@ public function __construct(ConsumersFactory $factory)
/**
* {@inheritdoc}
*/
protected function configure()
protected function configure(): void
{
$this
->setDescription('Consume MySQL replication events and execute listeners')
Expand Down Expand Up @@ -89,14 +89,14 @@ private function parseOptions(InputInterface $input): void
}

if ($input->getOption('memory') !== null) {
$this->maxMemory = $this->convertToBytes($input->getOption('memory'));
$this->maxMemory = $this->convertToBytes((string) $input->getOption('memory'));
}
}

private function runConsumer(EntityEventsConsumer $consumer): void
{
pcntl_async_signals(true);
pcntl_signal(SIGINT, function () use($consumer) {
pcntl_signal(SIGINT, function () use ($consumer) {
$this->running = false;
});

Expand Down
37 changes: 28 additions & 9 deletions src/EntityEventsConsumer.php
Expand Up @@ -56,12 +56,12 @@ final class EntityEventsConsumer extends EventSubscribers
private $configurator;

/**
* @var EntityEventsListener[]
* @var array<class-string, EntityEventsListener>
*/
private $entityListenersByEntityClass = [];

/**
* @var EntityEventsListener[]
* @var array<string, EntityEventsListener>
*/
private $entityListenersByTable = [];

Expand Down Expand Up @@ -109,7 +109,7 @@ public function __construct(ServiceLocator $prime, ?string $logPositionFile = nu
* ;
* </code>
*
* @param string $entityClass The entity class name
* @param class-string $entityClass The entity class name
*
* @return EntityEventsListener The listener instance
*/
Expand All @@ -122,7 +122,10 @@ public function forEntity(string $entityClass): EntityEventsListener
$repository = $this->prime->repository($entityClass);
$listener = new EntityEventsListener($repository);

return $this->entityListenersByTable[$repository->metadata()->table()] = $this->entityListenersByEntityClass[$entityClass] = $listener;
return $this->entityListenersByTable[$repository->metadata()->table()]
= $this->entityListenersByEntityClass[$entityClass]
= $listener
;
}

/**
Expand All @@ -134,6 +137,7 @@ public function onDelete(DeleteRowsDTO $event): void

$listener = $this->entityListenersByTable[$event->getTableMap()->getTable()];

/** @var array $value */
foreach ($event->getValues() as $value) {
$listener->onDelete($value);
}
Expand All @@ -148,6 +152,7 @@ public function onWrite(WriteRowsDTO $event): void

$listener = $this->entityListenersByTable[$event->getTableMap()->getTable()];

/** @var array $value */
foreach ($event->getValues() as $value) {
$listener->onWrite($value);
}
Expand All @@ -162,6 +167,7 @@ public function onUpdate(UpdateRowsDTO $event): void

$listener = $this->entityListenersByTable[$event->getTableMap()->getTable()];

/** @var array{before: array, after: array} $value */
foreach ($event->getValues() as $value) {
$listener->onUpdate($value);
}
Expand All @@ -177,6 +183,8 @@ protected function allEvents(EventDTO $event): void

/**
* Configure the consumer
*
* @psalm-assert MySQLReplicationFactory $this->binLogStream
*/
public function start(): void
{
Expand All @@ -202,6 +210,8 @@ public function consume(): void

/**
* Unconfigure the consumer, and save the last consumed event
*
* @psalm-assert null $this->binLogStream
*/
public function stop(): void
{
Expand Down Expand Up @@ -230,12 +240,18 @@ private function config(): Config

if ($connection instanceof Connection) {
if ($connection->getDatabasePlatform()->getName() !== 'mysql') {
throw new InvalidArgumentException(sprintf('The connection "%s" must be a MySQL connection', $connection->getName()));
throw new InvalidArgumentException(sprintf(
'The connection "%s" must be a MySQL connection',
$connection->getName()
));
}

$username = $username ?? $connection->getParams()['user'] ?? null;
$password = $password ?? $connection->getParams()['password'] ?? null;
$host = $host ?? $connection->getParams()['host'] ?? null;
/** @psalm-suppress InternalMethod */
$params = $connection->getParams();

$username = $username ?? $params['user'] ?? null;
$password = $password ?? $params['password'] ?? null;
$host = $host ?? $params['host'] ?? null;
}
}

Expand Down Expand Up @@ -281,7 +297,10 @@ private function loadLastPosition(): void
return;
}

$content = unserialize(file_get_contents($this->logPositionFile), ['allowed_classes' => [BinLogCurrent::class]]);
$content = unserialize(
file_get_contents($this->logPositionFile),
['allowed_classes' => [BinLogCurrent::class]]
);

if (!$content instanceof BinLogCurrent) {
return;
Expand Down
3 changes: 3 additions & 0 deletions src/EntityEventsListener.php
Expand Up @@ -10,6 +10,8 @@

/**
* Listener for database entities writes
*
* @todo set entity template when feature psalm is merged
*/
final class EntityEventsListener
{
Expand Down Expand Up @@ -50,6 +52,7 @@ public function onWrite(array $value): void
}

/**
* @param array{before: array, after: array} $value
* @internal
*/
public function onUpdate(array $value): void
Expand Down
2 changes: 1 addition & 1 deletion src/Factory/ConsumerConfiguration.php
Expand Up @@ -39,7 +39,7 @@ public function logPositionFile(): ?string
*
* @param ConfigBuilder $builder
*/
public function configure(ConfigBuilder $builder)
public function configure(ConfigBuilder $builder): void
{
foreach ($this->config as $item => $value) {
$method = 'with' . $item;
Expand Down
18 changes: 15 additions & 3 deletions src/Factory/ConsumersFactory.php
Expand Up @@ -93,7 +93,10 @@ public function forConnection(string $connection): EntityEventsConsumer
$listeners = $this->filterListenersForConnection($connection);

if (empty($listeners)) {
throw new InvalidArgumentException('Cannot found any entity listeners for connection name "' . $connection . '"');
throw new InvalidArgumentException(sprintf(
'Cannot found any entity listeners for connection name "%s"',
$connection
));
}


Expand Down Expand Up @@ -124,7 +127,10 @@ public function forConnection(string $connection): EntityEventsConsumer
*/
public function configure(string $connection, $config): void
{
$this->config[$connection] = $config instanceof ConsumerConfiguration ? $config : new ConsumerConfiguration($config);
$this->config[$connection] = $config instanceof ConsumerConfiguration
? $config
: new ConsumerConfiguration($config)
;
}

/**
Expand All @@ -151,8 +157,14 @@ private function filterListenersForConnection(string $connection): array
foreach ($this->listeners as $listener) {
$repository = $this->prime->repository($listener->entityClass());

// @todo remove when psalm feature is merged on prime
/** @psalm-suppress DocblockTypeContradiction */
if (!$repository) {
throw new LogicException(sprintf('The entity "%s" cannot be found for the listener "%s"', $listener->entityClass(), get_class($listener)));
throw new LogicException(sprintf(
'The entity "%s" cannot be found for the listener "%s"',
$listener->entityClass(),
get_class($listener)
));
}

if ($repository->metadata()->connection === $connection) {
Expand Down

0 comments on commit e4d4697

Please sign in to comment.