From 66b736186a770210506d628a9cc81ae7aeb5a8a0 Mon Sep 17 00:00:00 2001 From: Eugene Ivanov <93479789+evgeek@users.noreply.github.com> Date: Mon, 27 Mar 2023 11:32:11 +0300 Subject: [PATCH] Added support for Laravel 10 (#19) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ⚠️ Backward compatibility break: Monolog interfaces have changed - $record is now a LogRecord, not an array --- .github/workflows/ci.yml | 33 ++------- .gitignore | 1 + README.md | 13 ++-- composer.json | 20 ++--- ecs.php | 74 ++++++++++++------- ecs.yml | 15 ---- phpunit.xml.dist | 33 ++++----- .../Laravel/Console/PidManager.php | 8 +- .../Laravel/Console/ProcessManagerCommand.php | 9 +-- .../Laravel/InfluxDBLogChannel.php | 3 +- src/Integration/Laravel/Jobs/PublishJob.php | 11 +-- .../Laravel/Jobs/ReceiveMessage.php | 8 +- .../Publishers/EnsureConsistencyPublisher.php | 8 +- .../Laravel/Publishers/QueuePublisher.php | 11 +-- .../Receive/MessageData/MessageData.php | 14 ++-- .../MessageData/MessageDataRetriever.php | 8 +- src/Integration/Laravel/Receive/Receiver.php | 8 +- .../Laravel/Receive/Upserter/Upserter.php | 8 +- .../QueueReceivedMessageHandler.php | 8 +- src/Integration/Laravel/Syncer.php | 18 ++--- src/Integration/Laravel/TableSyncObserver.php | 8 +- .../Laravel/TableSyncServiceProvider.php | 12 +-- src/Integration/Laravel/TableSyncable.php | 4 +- .../Laravel/TelegrafLogChannel.php | 3 +- src/Messages/PublishMessage.php | 24 +++--- src/Messages/ReceivedMessage.php | 29 ++------ src/Monolog/Formatter/InfluxDBFormatter.php | 12 ++- .../Formatter/JsonTableSyncFormatter.php | 20 ++--- .../Formatter/LineTableSyncFormatter.php | 17 ++--- src/Monolog/Formatter/TableSyncFormatter.php | 24 +++--- src/Monolog/Handler/InfluxDBHandler.php | 21 ++---- src/Monolog/Handler/TelegrafHandler.php | 28 ++++--- src/Rabbit/ChannelContainer.php | 13 ++-- src/Rabbit/Config/Consumer.php | 15 ++-- src/Rabbit/Config/PublishMessage.php | 11 +-- src/Rabbit/Config/Publisher.php | 15 +--- src/Rabbit/ConnectionContainer.php | 42 +++-------- src/Rabbit/Consumer.php | 19 ++--- src/Rabbit/MessageBuilder.php | 7 +- src/Rabbit/Publisher.php | 17 +---- tests/unit/Logging/FormatterTest.php | 33 +++++---- tests/unit/Messages/PublishMessageTest.php | 2 +- tests/unit/Rabbit/MessageBuilderTest.php | 2 +- 43 files changed, 286 insertions(+), 403 deletions(-) delete mode 100644 ecs.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8de2036..e5ec818 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,7 +26,7 @@ jobs: strategy: matrix: operating_system: [ubuntu-latest] - php_versions: ['7.4'] + php_versions: ['8.1'] fail-fast: false env: PHP_CS_FIXER_FUTURE_MODE: '0' @@ -68,31 +68,12 @@ jobs: strategy: fail-fast: false matrix: - coverage: [false] + coverage: [true] experimental: [false] operating_system: [ubuntu-latest] - postgres: ['11'] - laravel: ['^6.0', '^7.0', '^8.0'] - php_versions: ['7.3', '7.4'] - include: - - operating_system: ubuntu-latest - postgres: '11' - php_versions: '7.4' - experimental: false - laravel: '^8.0' - coverage: true - - operating_system: ubuntu-latest - postgres: '12' - php_versions: '8.0' - laravel: '^8.0' - experimental: false - coverage: false - - operating_system: ubuntu-latest - postgres: '13' - php_versions: '8.0' - laravel: '^8.0' - experimental: true - coverage: false + postgres: ['11', '12', '13', '14', '15'] + laravel: ['^10'] + php_versions: ['8.1', '8.2'] runs-on: '${{ matrix.operating_system }}' services: postgres: @@ -152,9 +133,9 @@ jobs: -e "s/\${HOST}/${{ env.DB_HOST }}/" \ phpunit.xml.dist > phpunit.xml if [[ ${{ matrix.coverage }} == true ]]; then - ./vendor/bin/phpunit --verbose --stderr --coverage-clover build/logs/clover.xml --coverage-text + ./vendor/bin/phpunit --stderr --coverage-clover build/logs/clover.xml --coverage-text else - ./vendor/bin/phpunit --verbose --stderr + ./vendor/bin/phpunit --stderr fi working-directory: './' - name: 'Upload coverage results to Coveralls' diff --git a/.gitignore b/.gitignore index d838c5a..2035b7c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ phpunit.xml .phpunit.result.cache .DS_Store composer.lock +/.phpunit.cache \ No newline at end of file diff --git a/README.md b/README.md index 024059f..6e3a43c 100644 --- a/README.md +++ b/README.md @@ -13,13 +13,16 @@ ## Installation -``` + +```shell composer require umbrellio/php-table-sync ``` ## Usage + Let's describe the model that needs to be synchronized using an example `User.php` -``` + +```php ... User extends Model implements SyncableModel { @@ -48,7 +51,7 @@ When the model changes, the data will be sent according to the rules of `TableSy ## Logging Logging based on the Monolog package and contains some extensions for it. - specify the logging channel in `config/table_sync.php` -``` +```php ... 'log' => [ 'channel' => 'table_sync', @@ -56,7 +59,7 @@ Logging based on the Monolog package and contains some extensions for it. ... ``` - and describe this channel in `config/logging.php` -``` +```php ... 'table_sync' => [ 'driver' => 'stack', @@ -80,7 +83,7 @@ Logging based on the Monolog package and contains some extensions for it. ##### You can use the built-in `LineTableSyncFormatter::class` with the available parameters: `%datetime%` `%message%` `%direction%` `%model%` `%event%` `%routing%` `%attributes%` `%exception%` ###### Driver `influxdb` is an additional option and is not required to add in config -``` +```php ... 'table_sync' => [ 'driver' => 'daily', diff --git a/composer.json b/composer.json index c6b5678..ffe26ed 100644 --- a/composer.json +++ b/composer.json @@ -13,23 +13,23 @@ "license": "MIT", "type": "library", "require": { - "php": "^7.3|^7.4|^8.0", + "php": "^8.1", "ext-json": "*", - "php-amqplib/php-amqplib": "^2.8 || ^3.0", - "laravel/framework": "^5.8|^6.0|^7.0|^8.0|^9.0", - "thecodingmachine/safe": "^0.1.6|^1.0", - "umbrellio/laravel-heavy-jobs": "^1.0.3|^2.0|^3.0", - "monolog/monolog": "^1.1|^2.0", + "ext-posix": "*", + "php-amqplib/php-amqplib": "^3.0", + "laravel/framework": "^10.0", + "thecodingmachine/safe": "^2.0", + "umbrellio/laravel-heavy-jobs": "^3.0", + "monolog/monolog": "^3.0", "influxdb/influxdb-php": "^1.15" }, "require-dev": { - "phpunit/phpunit": "^7.3|^8.5|^9.4", + "phpunit/phpunit": "^10.0", "php-mock/php-mock": "^2.0", - "orchestra/testbench": "^3.8|^4.8|^5.7|^6.2|^7.0", + "orchestra/testbench": "^8.0", "mockery/mockery": "^1.0", "mikey179/vfsstream": "^1.6", - "umbrellio/code-style-php": "^1.0", - "symplify/easy-coding-standard": "^9.3.15", + "symplify/easy-coding-standard": "^11.0", "laravel/legacy-factories": "*", "php-coveralls/php-coveralls": "^2.1", "squizlabs/php_codesniffer": "^3.5" diff --git a/ecs.php b/ecs.php index cd87314..4c9921b 100644 --- a/ecs.php +++ b/ecs.php @@ -2,31 +2,53 @@ declare(strict_types=1); -use PhpCsFixer\Fixer\Operator\BinaryOperatorSpacesFixer; +use PHP_CodeSniffer\Standards\Generic\Sniffs\CodeAnalysis\AssignmentInConditionSniff; +use PhpCsFixer\Fixer\ClassNotation\ClassAttributesSeparationFixer; +use PhpCsFixer\Fixer\ClassNotation\SingleTraitInsertPerStatementFixer; +use PhpCsFixer\Fixer\FunctionNotation\MethodArgumentSpaceFixer; +use PhpCsFixer\Fixer\Operator\NotOperatorWithSuccessorSpaceFixer; +use PhpCsFixer\Fixer\Phpdoc\NoSuperfluousPhpdocTagsFixer; +use PhpCsFixer\Fixer\Phpdoc\PhpdocLineSpanFixer; +use PhpCsFixer\Fixer\Phpdoc\PhpdocTrimFixer; use PhpCsFixer\Fixer\PhpUnit\PhpUnitTestAnnotationFixer; -use PhpCsFixer\Fixer\Strict\DeclareStrictTypesFixer; -use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; - -return static function (ContainerConfigurator $containerConfigurator): void { - $containerConfigurator->import(__DIR__ . '/vendor/umbrellio/code-style-php/umbrellio-cs.php'); - - $services = $containerConfigurator->services(); - - $services->set(PhpUnitTestAnnotationFixer::class) - ->call('configure', [[ - 'style' => 'annotation', - ]]); - - $services->set(DeclareStrictTypesFixer::class); - - $services->set(BinaryOperatorSpacesFixer::class) - ->call('configure', [[ - 'default' => 'single_space', - ]]); - - $parameters = $containerConfigurator->parameters(); - - $parameters->set('cache_directory', '.ecs_cache'); - - $parameters->set('exclude_files', ['vendor/*', 'database/*']); +use PhpCsFixer\Fixer\StringNotation\ExplicitStringVariableFixer; +use PhpCsFixer\Fixer\Whitespace\ArrayIndentationFixer; +use PhpCsFixer\Fixer\Whitespace\MethodChainingIndentationFixer; +use Symplify\CodingStandard\Fixer\ArrayNotation\ArrayOpenerAndCloserNewlineFixer; +use Symplify\CodingStandard\Fixer\LineLength\LineLengthFixer; +use Symplify\CodingStandard\Fixer\Spacing\MethodChainingNewlineFixer; +use Symplify\EasyCodingStandard\Config\ECSConfig; +use Symplify\EasyCodingStandard\ValueObject\Set\SetList; + +return static function (ECSConfig $ecsConfig): void { + $ecsConfig->paths([__DIR__ . '/app', __DIR__ . '/tests']); + $ecsConfig->parallel(); + + $ecsConfig->sets([SetList::PSR_12]); + $ecsConfig->sets([SetList::CLEAN_CODE]); + $ecsConfig->sets([SetList::COMMON]); + $ecsConfig->sets([SetList::SYMPLIFY]); + $ecsConfig->sets([SetList::STRICT]); + + $ecsConfig->skip([ + 'vendor/*', + 'database/*', + '.ecs_cache/*', + + ArrayIndentationFixer::class, + MethodArgumentSpaceFixer::class, + SingleTraitInsertPerStatementFixer::class, + PhpdocTrimFixer::class, + AssignmentInConditionSniff::class, + MethodChainingNewlineFixer::class, + ArrayOpenerAndCloserNewlineFixer::class, + NotOperatorWithSuccessorSpaceFixer::class, + PhpdocLineSpanFixer::class, + MethodChainingIndentationFixer::class, + ClassAttributesSeparationFixer::class, + LineLengthFixer::class, + NoSuperfluousPhpdocTagsFixer::class, + ExplicitStringVariableFixer::class, + PhpUnitTestAnnotationFixer::class, + ]); }; diff --git a/ecs.yml b/ecs.yml deleted file mode 100644 index 601e1ad..0000000 --- a/ecs.yml +++ /dev/null @@ -1,15 +0,0 @@ -imports: - - { resource: vendor/umbrellio/code-style-php/umbrellio-cs.yml } - -services: - PhpCsFixer\Fixer\PhpUnit\PhpUnitTestAnnotationFixer: - style: annotation - PhpCsFixer\Fixer\Strict\DeclareStrictTypesFixer: ~ - PhpCsFixer\Fixer\Operator\BinaryOperatorSpacesFixer: - default: single_space - -parameters: - cache_directory: .ecs_cache - exclude_files: - - vendor/* - - database/* diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 0e0d032..33eddc3 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,30 +1,27 @@ - - + + ./src - - ./database - - - + + + ./database + + - + - - - - + + + + diff --git a/src/Integration/Laravel/Console/PidManager.php b/src/Integration/Laravel/Console/PidManager.php index e163eae..10fd0c9 100644 --- a/src/Integration/Laravel/Console/PidManager.php +++ b/src/Integration/Laravel/Console/PidManager.php @@ -8,11 +8,9 @@ class PidManager { - private $pathToPidFile; - - public function __construct(string $pathToPidFile) - { - $this->pathToPidFile = $pathToPidFile; + public function __construct( + private readonly string $pathToPidFile + ) { } public function pidExists(): bool diff --git a/src/Integration/Laravel/Console/ProcessManagerCommand.php b/src/Integration/Laravel/Console/ProcessManagerCommand.php index 6e75399..74657d6 100644 --- a/src/Integration/Laravel/Console/ProcessManagerCommand.php +++ b/src/Integration/Laravel/Console/ProcessManagerCommand.php @@ -8,12 +8,9 @@ abstract class ProcessManagerCommand extends Command { - protected $pidManager; - - public function __construct(PidManager $pidManager) - { + public function __construct( + protected PidManager $pidManager + ) { parent::__construct(); - - $this->pidManager = $pidManager; } } diff --git a/src/Integration/Laravel/InfluxDBLogChannel.php b/src/Integration/Laravel/InfluxDBLogChannel.php index 78761c7..ddfc66a 100644 --- a/src/Integration/Laravel/InfluxDBLogChannel.php +++ b/src/Integration/Laravel/InfluxDBLogChannel.php @@ -6,6 +6,7 @@ use Illuminate\Log\LogManager; use InfluxDB\Database; +use Monolog\Level; use Monolog\Logger; use Psr\Log\LoggerInterface; use Umbrellio\TableSync\Monolog\Handler\InfluxDBHandler; @@ -17,7 +18,7 @@ public function __invoke(array $config): LoggerInterface $handler = new InfluxDBHandler( $this->app->make(Database::class), $config['measurement'] ?? null, - $config['level'] ?? Logger::INFO, + $config['level'] ?? Level::Info, $config['bubble'] ?? true ); diff --git a/src/Integration/Laravel/Jobs/PublishJob.php b/src/Integration/Laravel/Jobs/PublishJob.php index 5d8a433..b761a7d 100644 --- a/src/Integration/Laravel/Jobs/PublishJob.php +++ b/src/Integration/Laravel/Jobs/PublishJob.php @@ -16,14 +16,11 @@ final class PublishJob implements ShouldQueue, ShouldStorePayload use HeavyJobsEnabledTrait; use Queueable; - private $publisherClass; - private $message; - - public function __construct(string $publisherClass, PublishMessage $message) - { + public function __construct( + private readonly string $publisherClass, + private PublishMessage $message + ) { $this->queue = Config::get('table_sync.publish_job_queue', ''); - $this->publisherClass = $publisherClass; - $this->message = $message; } public function handle(): void diff --git a/src/Integration/Laravel/Jobs/ReceiveMessage.php b/src/Integration/Laravel/Jobs/ReceiveMessage.php index ef8b7cd..e7bfc7d 100644 --- a/src/Integration/Laravel/Jobs/ReceiveMessage.php +++ b/src/Integration/Laravel/Jobs/ReceiveMessage.php @@ -16,12 +16,10 @@ final class ReceiveMessage implements ShouldQueue, ShouldStorePayload use HeavyJobsEnabledTrait; use Queueable; - private $message; - - public function __construct(ReceivedMessage $message) - { + public function __construct( + private readonly ReceivedMessage $message + ) { $this->queue = Config::get('table_sync.receive_job_queue', ''); - $this->message = $message; } public function handle(Receiver $receiver): void diff --git a/src/Integration/Laravel/Publishers/EnsureConsistencyPublisher.php b/src/Integration/Laravel/Publishers/EnsureConsistencyPublisher.php index c93bf24..5dbe6a4 100644 --- a/src/Integration/Laravel/Publishers/EnsureConsistencyPublisher.php +++ b/src/Integration/Laravel/Publishers/EnsureConsistencyPublisher.php @@ -11,11 +11,9 @@ final class EnsureConsistencyPublisher implements Publisher { - private $publisher; - - public function __construct(Publisher $publisher) - { - $this->publisher = $publisher; + public function __construct( + private readonly Publisher $publisher + ) { } public function publish(PublishMessage $message): void diff --git a/src/Integration/Laravel/Publishers/QueuePublisher.php b/src/Integration/Laravel/Publishers/QueuePublisher.php index c4f1168..657d934 100644 --- a/src/Integration/Laravel/Publishers/QueuePublisher.php +++ b/src/Integration/Laravel/Publishers/QueuePublisher.php @@ -11,13 +11,10 @@ final class QueuePublisher implements Publisher { - private $publisher; - private $dispatcher; - - public function __construct(Publisher $publisher, Dispatcher $dispatcher) - { - $this->publisher = $publisher; - $this->dispatcher = $dispatcher; + public function __construct( + private readonly Publisher $publisher, + private readonly Dispatcher $dispatcher + ) { } public function publish(PublishMessage $message): void diff --git a/src/Integration/Laravel/Receive/MessageData/MessageData.php b/src/Integration/Laravel/Receive/MessageData/MessageData.php index 19e0bcf..55afeec 100644 --- a/src/Integration/Laravel/Receive/MessageData/MessageData.php +++ b/src/Integration/Laravel/Receive/MessageData/MessageData.php @@ -6,15 +6,11 @@ class MessageData { - private $table; - private $targetKeys; - private $data; - - public function __construct(string $table, array $targetKeys, array $data) - { - $this->table = $table; - $this->targetKeys = $targetKeys; - $this->data = $data; + public function __construct( + private readonly string $table, + private readonly array $targetKeys, + private readonly array $data + ) { } public function getTable(): string diff --git a/src/Integration/Laravel/Receive/MessageData/MessageDataRetriever.php b/src/Integration/Laravel/Receive/MessageData/MessageDataRetriever.php index cfdcce8..34a72a5 100644 --- a/src/Integration/Laravel/Receive/MessageData/MessageDataRetriever.php +++ b/src/Integration/Laravel/Receive/MessageData/MessageDataRetriever.php @@ -10,12 +10,10 @@ class MessageDataRetriever { - private $config; - // todo: config should be object - public function __construct(array $config) - { - $this->config = $config; + public function __construct( + private readonly array $config + ) { } public function retrieve(ReceivedMessage $message): MessageData diff --git a/src/Integration/Laravel/Receive/Receiver.php b/src/Integration/Laravel/Receive/Receiver.php index dbeb4a3..50c8c74 100644 --- a/src/Integration/Laravel/Receive/Receiver.php +++ b/src/Integration/Laravel/Receive/Receiver.php @@ -12,11 +12,9 @@ class Receiver { - private $dataRetriever; - - public function __construct(MessageDataRetriever $dataRetriever) - { - $this->dataRetriever = $dataRetriever; + public function __construct( + private readonly MessageDataRetriever $dataRetriever + ) { } public function receive(ReceivedMessage $message): void diff --git a/src/Integration/Laravel/Receive/Upserter/Upserter.php b/src/Integration/Laravel/Receive/Upserter/Upserter.php index 74994cf..171ae37 100644 --- a/src/Integration/Laravel/Receive/Upserter/Upserter.php +++ b/src/Integration/Laravel/Receive/Upserter/Upserter.php @@ -10,11 +10,9 @@ class Upserter { - private $conflictConditionResolver; - - public function __construct(ConflictConditionResolverContract $conflictConditionResolver) - { - $this->conflictConditionResolver = $conflictConditionResolver; + public function __construct( + private readonly ConflictConditionResolverContract $conflictConditionResolver + ) { } // todo via modern expressive not existing query builder diff --git a/src/Integration/Laravel/ReceivedMessageHandlers/QueueReceivedMessageHandler.php b/src/Integration/Laravel/ReceivedMessageHandlers/QueueReceivedMessageHandler.php index 82e925f..4d969c5 100644 --- a/src/Integration/Laravel/ReceivedMessageHandlers/QueueReceivedMessageHandler.php +++ b/src/Integration/Laravel/ReceivedMessageHandlers/QueueReceivedMessageHandler.php @@ -11,11 +11,9 @@ final class QueueReceivedMessageHandler implements ReceivedMessageHandler { - private $dispatcher; - - public function __construct(Dispatcher $dispatcher) - { - $this->dispatcher = $dispatcher; + public function __construct( + private readonly Dispatcher $dispatcher + ) { } public function handle(ReceivedMessage $message): void diff --git a/src/Integration/Laravel/Syncer.php b/src/Integration/Laravel/Syncer.php index 0833f52..e34ebdf 100644 --- a/src/Integration/Laravel/Syncer.php +++ b/src/Integration/Laravel/Syncer.php @@ -10,30 +10,24 @@ class Syncer { - private const EVENT_CREATED = 'created'; - private const EVENT_UPDATED = 'updated'; - private const EVENT_DELETED = 'deleted'; - - private $publisher; - - public function __construct(Publisher $publisher) - { - $this->publisher = $publisher; + public function __construct( + private readonly Publisher $publisher + ) { } public function syncCreated(SyncableModel $model): void { - $this->syncTable($model, self::EVENT_CREATED); + $this->syncTable($model, PublishMessage::EVENT_CREATED); } public function syncUpdated(SyncableModel $model): void { - $this->syncTable($model, self::EVENT_UPDATED); + $this->syncTable($model, PublishMessage::EVENT_UPDATED); } public function syncDeleted(SyncableModel $model): void { - $this->syncTable($model, self::EVENT_DELETED); + $this->syncTable($model, PublishMessage::EVENT_DELETED); } private function syncTable(SyncableModel $model, string $event): void diff --git a/src/Integration/Laravel/TableSyncObserver.php b/src/Integration/Laravel/TableSyncObserver.php index 6f47231..edc01c7 100644 --- a/src/Integration/Laravel/TableSyncObserver.php +++ b/src/Integration/Laravel/TableSyncObserver.php @@ -8,11 +8,9 @@ class TableSyncObserver { - private $syncer; - - public function __construct(Syncer $syncer) - { - $this->syncer = $syncer; + public function __construct( + private readonly Syncer $syncer + ) { } public function created(SyncableModel $model): void diff --git a/src/Integration/Laravel/TableSyncServiceProvider.php b/src/Integration/Laravel/TableSyncServiceProvider.php index 62f7cef..607d82f 100644 --- a/src/Integration/Laravel/TableSyncServiceProvider.php +++ b/src/Integration/Laravel/TableSyncServiceProvider.php @@ -24,12 +24,12 @@ class TableSyncServiceProvider extends ServiceProvider { - public $bindings = [ + public array $bindings = [ ConflictConditionResolverContract::class => ByTargetKeysResolver::class, ]; protected $defer = true; - public function boot() + public function boot(): void { $config = __DIR__ . '/config/table_sync.php'; @@ -38,7 +38,7 @@ public function boot() ], 'config'); } - public function configureChannel() + public function configureChannel(): void { $this->app->bind(ChannelContainer::class, function ($app) { $channel = new ChannelContainer($app->make(ConnectionContainer::class)); @@ -47,7 +47,7 @@ public function configureChannel() }); } - public function register() + public function register(): void { $publishConfig = ConfigRepository::get('table_sync.publish'); @@ -71,12 +71,12 @@ public function register() $this->configureChannel(); } - public function provides() + public function provides(): array { return [Publisher::class]; } - protected function registerCommands() + protected function registerCommands(): void { if ($this->app->runningInConsole()) { $this->commands([ diff --git a/src/Integration/Laravel/TableSyncable.php b/src/Integration/Laravel/TableSyncable.php index 2c0d104..d5f2eee 100644 --- a/src/Integration/Laravel/TableSyncable.php +++ b/src/Integration/Laravel/TableSyncable.php @@ -6,9 +6,9 @@ trait TableSyncable { - public static $isTableSyncEnabled = true; + public static bool $isTableSyncEnabled = true; - public static function bootTableSyncable() + public static function bootTableSyncable(): void { if (static::$isTableSyncEnabled) { static::observe(TableSyncObserver::class); diff --git a/src/Integration/Laravel/TelegrafLogChannel.php b/src/Integration/Laravel/TelegrafLogChannel.php index 63ae49f..a8f58b7 100644 --- a/src/Integration/Laravel/TelegrafLogChannel.php +++ b/src/Integration/Laravel/TelegrafLogChannel.php @@ -5,6 +5,7 @@ namespace Umbrellio\TableSync\Integration\Laravel; use Illuminate\Log\LogManager; +use Monolog\Level; use Monolog\Logger; use Psr\Log\LoggerInterface; use Umbrellio\TableSync\Monolog\Handler\TelegrafHandler; @@ -17,7 +18,7 @@ public function __invoke(array $config): LoggerInterface config('telegraf.host'), config('telegraf.port'), $config['measurement'] ?? null, - $config['level'] ?? Logger::INFO, + $config['level'] ?? Level::Info, $config['bubble'] ?? true ); diff --git a/src/Messages/PublishMessage.php b/src/Messages/PublishMessage.php index f657d8c..4ff5cf5 100644 --- a/src/Messages/PublishMessage.php +++ b/src/Messages/PublishMessage.php @@ -6,25 +6,21 @@ class PublishMessage { - public const EVENT_DESTROYED = 'deleted'; public const EVENT_CREATED = 'created'; - - private $className; - private $routingKey; - private $event; - private $attributes; - - public function __construct(string $className, string $event, string $routingKey, array $attributes = []) - { - $this->className = $className; - $this->routingKey = $routingKey; - $this->event = $event; - $this->attributes = $attributes; + public const EVENT_UPDATED = 'updated'; + public const EVENT_DELETED = 'deleted'; + + public function __construct( + private readonly string $className, + private readonly string $event, + private readonly string $routingKey, + private readonly array $attributes = [] + ) { } public function isDestroyed(): bool { - return $this->event === self::EVENT_DESTROYED; + return $this->event === self::EVENT_DELETED; } public function isCreated(): bool diff --git a/src/Messages/ReceivedMessage.php b/src/Messages/ReceivedMessage.php index 30062da..7bf6831 100644 --- a/src/Messages/ReceivedMessage.php +++ b/src/Messages/ReceivedMessage.php @@ -6,30 +6,15 @@ class ReceivedMessage { - private $event; - private $model; - private $attributes; - private $version; - private $metadata; - private $appId; - private $headers; - public function __construct( - string $event, - string $model, - array $attributes, - float $version, - array $metadata, - string $appId, - array $headers = [] + private readonly string $event, + private readonly string $model, + private readonly array $attributes, + private readonly float $version, + private readonly array $metadata, + private readonly string $appId, + private readonly array $headers = [] ) { - $this->event = $event; - $this->model = $model; - $this->attributes = $attributes; - $this->version = $version; - $this->metadata = $metadata; - $this->appId = $appId; - $this->headers = $headers; } public function getEvent(): string diff --git a/src/Monolog/Formatter/InfluxDBFormatter.php b/src/Monolog/Formatter/InfluxDBFormatter.php index d85703a..fbea9c7 100644 --- a/src/Monolog/Formatter/InfluxDBFormatter.php +++ b/src/Monolog/Formatter/InfluxDBFormatter.php @@ -5,19 +5,17 @@ namespace Umbrellio\TableSync\Monolog\Formatter; use InfluxDB\Point; +use Monolog\LogRecord; class InfluxDBFormatter extends TableSyncFormatter { - private $measurement; - - public function __construct(string $measurement) - { + public function __construct( + private readonly string $measurement + ) { parent::__construct(); - - $this->measurement = $measurement; } - public function format(array $record): array + public function format(LogRecord $record): array { return [ new Point( diff --git a/src/Monolog/Formatter/JsonTableSyncFormatter.php b/src/Monolog/Formatter/JsonTableSyncFormatter.php index f1ab0f6..3d07ccf 100644 --- a/src/Monolog/Formatter/JsonTableSyncFormatter.php +++ b/src/Monolog/Formatter/JsonTableSyncFormatter.php @@ -4,21 +4,23 @@ namespace Umbrellio\TableSync\Monolog\Formatter; +use Monolog\LogRecord; use Monolog\Utils; class JsonTableSyncFormatter extends TableSyncFormatter { - public function format(array $record) + /** @return string */ + public function format(LogRecord $record) { - $record = parent::format($record); + $formattedRecord = parent::format($record); $formatted = [ - 'datetime' => $record['datetime'], - 'message' => $record['message'], - 'direction' => $record['direction'], - 'routing' => $record['routing'], - 'model' => $record['model'], - 'event' => $record['event'], - 'count' => count($record['attributes']), + 'datetime' => $formattedRecord['datetime'], + 'message' => $formattedRecord['message'], + 'direction' => $formattedRecord['direction'], + 'routing' => $formattedRecord['routing'], + 'model' => $formattedRecord['model'], + 'event' => $formattedRecord['event'], + 'count' => count($formattedRecord['attributes']), ]; return Utils::jsonEncode($formatted, Utils::DEFAULT_JSON_FLAGS, true) . "\n"; diff --git a/src/Monolog/Formatter/LineTableSyncFormatter.php b/src/Monolog/Formatter/LineTableSyncFormatter.php index 489d71c..f827686 100644 --- a/src/Monolog/Formatter/LineTableSyncFormatter.php +++ b/src/Monolog/Formatter/LineTableSyncFormatter.php @@ -4,20 +4,17 @@ namespace Umbrellio\TableSync\Monolog\Formatter; +use Monolog\LogRecord; + class LineTableSyncFormatter extends TableSyncFormatter { - private $format = '[%datetime%] %message% %routing% %model% %event%'; - - public function __construct(?string $format = null) - { + public function __construct( + private readonly string $format = '[%datetime%] %message% %routing% %model% %event%' + ) { parent::__construct(); - - if ($format !== null) { - $this->format = $format; - } } - public function format(array $record): string + public function format(LogRecord $record): string { $vars = parent::format($record); @@ -29,7 +26,7 @@ public function format(array $record): string continue; } - if (strpos($output, "%{$var}%") !== false) { + if (str_contains($output, "%{$var}%")) { $output = str_replace("%{$var}%", $value, $output); } } diff --git a/src/Monolog/Formatter/TableSyncFormatter.php b/src/Monolog/Formatter/TableSyncFormatter.php index ccf453a..9568f0c 100644 --- a/src/Monolog/Formatter/TableSyncFormatter.php +++ b/src/Monolog/Formatter/TableSyncFormatter.php @@ -5,13 +5,15 @@ namespace Umbrellio\TableSync\Monolog\Formatter; use Monolog\Formatter\NormalizerFormatter; +use Monolog\LogRecord; class TableSyncFormatter extends NormalizerFormatter { - public function format(array $record) + /** @return array */ + public function format(LogRecord $record) { return [ - 'datetime' => (string) $record['datetime'], + 'datetime' => $record->datetime->format('Y-m-d\TH:i:s.uP'), 'message' => $record['message'], 'direction' => $this->getDirection($record), 'routing' => $this->getRoutingKey($record), @@ -22,27 +24,27 @@ public function format(array $record) ]; } - protected function getDirection(array $record): string + protected function getDirection(LogRecord $record): string { - return $record['context']['direction'] ?? ''; + return $record->context['direction'] ?? ''; } - protected function getRoutingKey(array $record): string + protected function getRoutingKey(LogRecord $record): string { - return $record['context']['routing_key'] ?? ''; + return $record->context['routing_key'] ?? ''; } - protected function getEventType(array $record): string + protected function getEventType(LogRecord $record): string { return $this->getBody($record)['event'] ?? ''; } - protected function getModel(array $record): string + protected function getModel(LogRecord $record): string { return $this->getBody($record)['model'] ?? ''; } - protected function getAttributes(array $record): array + protected function getAttributes(LogRecord $record): array { if (!$body = $this->getBody($record)) { return []; @@ -53,9 +55,9 @@ protected function getAttributes(array $record): array return $this->addVersions($attributes, $body['version']); } - protected function getBody(array $record): array + protected function getBody(LogRecord $record): array { - return (array) json_decode($record['context']['body'] ?? '', true); + return (array) json_decode($record->context['body'] ?? '', true); } private function wrapAttributes(array $attributes): array diff --git a/src/Monolog/Handler/InfluxDBHandler.php b/src/Monolog/Handler/InfluxDBHandler.php index 4f1490a..d8a4ac9 100644 --- a/src/Monolog/Handler/InfluxDBHandler.php +++ b/src/Monolog/Handler/InfluxDBHandler.php @@ -9,27 +9,20 @@ use Monolog\Formatter\FormatterInterface; use Monolog\Handler\AbstractProcessingHandler; use Monolog\Handler\HandlerInterface; -use Monolog\Logger; +use Monolog\Level; +use Monolog\LogRecord; use Umbrellio\TableSync\Monolog\Formatter\InfluxDBFormatter; use Umbrellio\TableSync\Monolog\Formatter\TableSyncFormatter; class InfluxDBHandler extends AbstractProcessingHandler { - public const POINT_MEASUREMENT = 'table_sync'; - - private $database; - private $measurement; - public function __construct( - Database $database, - ?string $measurement, - int $level = Logger::INFO, + private readonly Database $database, + private readonly string $measurement = 'table_sync', + int|string|Level $level = Level::Info, bool $bubble = true ) { parent::__construct($level, $bubble); - - $this->database = $database; - $this->measurement = $measurement ?? self::POINT_MEASUREMENT; } public function setFormatter(FormatterInterface $formatter): HandlerInterface @@ -41,9 +34,9 @@ public function setFormatter(FormatterInterface $formatter): HandlerInterface throw new InvalidArgumentException('InfluxDBHandler is only compatible with TableSyncFormatter'); } - protected function write(array $record): void + protected function write(LogRecord $record): void { - $this->database->writePoints($record['formatted']); + $this->database->writePoints($record->formatted); } protected function getDefaultFormatter(): FormatterInterface diff --git a/src/Monolog/Handler/TelegrafHandler.php b/src/Monolog/Handler/TelegrafHandler.php index 9bde70e..289d95b 100644 --- a/src/Monolog/Handler/TelegrafHandler.php +++ b/src/Monolog/Handler/TelegrafHandler.php @@ -7,26 +7,34 @@ use InfluxDB\Driver\UDP; use Monolog\Formatter\FormatterInterface; use Monolog\Handler\AbstractProcessingHandler; -use Monolog\Logger; +use Monolog\Level; +use Monolog\LogRecord; use Umbrellio\TableSync\Monolog\Formatter\InfluxDBFormatter; class TelegrafHandler extends AbstractProcessingHandler { - private $measurement; - private $socket; - - public function __construct($host, $port, ?string $measurement, $level = Logger::INFO, $bubble = true) - { + private UDP $socket; + + public function __construct( + $host, + $port, + private readonly string $measurement = 'table_sync', + int|string|Level $level = Level::Info, + $bubble = true + ) { parent::__construct($level, $bubble); - $this->measurement = $measurement ?? InfluxDBHandler::POINT_MEASUREMENT; $this->socket = new UDP($host, $port); } - protected function write(array $record): void + protected function write(LogRecord $record): void { - foreach ($record['formatted'] as $record) { - $this->socket->write((string) $record); + if (!is_iterable($record->formatted)) { + return; + } + + foreach ($record->formatted as $formatted) { + $this->socket->write((string) $formatted); } } diff --git a/src/Rabbit/ChannelContainer.php b/src/Rabbit/ChannelContainer.php index ad4ac3e..37d5af8 100644 --- a/src/Rabbit/ChannelContainer.php +++ b/src/Rabbit/ChannelContainer.php @@ -8,17 +8,16 @@ class ChannelContainer { - private $connectionContainer; - private $channel; - private $channelOptions = [ + private AMQPChannel $channel; + private array $channelOptions = [ 'prefetch_size' => null, 'prefetch_count' => 1, 'a_global' => true, ]; - public function __construct(ConnectionContainer $connectionContainer) - { - $this->connectionContainer = $connectionContainer; + public function __construct( + private readonly ConnectionContainer $connectionContainer + ) { } public function __destruct() @@ -28,7 +27,7 @@ public function __destruct() } } - public function setChannelOption($option) + public function setChannelOption($option): void { if (!empty($option['prefetch_size'])) { $this->channelOptions['prefetch_size'] = $option['prefetch_size']; diff --git a/src/Rabbit/Config/Consumer.php b/src/Rabbit/Config/Consumer.php index 400ac64..7412bad 100644 --- a/src/Rabbit/Config/Consumer.php +++ b/src/Rabbit/Config/Consumer.php @@ -8,16 +8,13 @@ class Consumer { - private $handler; - private $queue; - private $consumerTag; - private $microsecondsToSleep = 1000000; + private int $microsecondsToSleep = 1000000; - public function __construct(ReceivedMessageHandler $handler, string $queue, string $consumerTag = '') - { - $this->handler = $handler; - $this->queue = $queue; - $this->consumerTag = $consumerTag; + public function __construct( + private readonly ReceivedMessageHandler $handler, + private readonly string $queue, + private readonly string $consumerTag = '' + ) { } public function handler(): ReceivedMessageHandler diff --git a/src/Rabbit/Config/PublishMessage.php b/src/Rabbit/Config/PublishMessage.php index 351c0f0..ec292bd 100644 --- a/src/Rabbit/Config/PublishMessage.php +++ b/src/Rabbit/Config/PublishMessage.php @@ -8,13 +8,10 @@ class PublishMessage { - private $headers; - private $appId; - - public function __construct(string $appId, ?AMQPTable $headers = null) - { - $this->appId = $appId; - $this->headers = $headers; + public function __construct( + private readonly string $appId, + private readonly ?AMQPTable $headers = null + ) { } public function headers(): ?AMQPTable diff --git a/src/Rabbit/Config/Publisher.php b/src/Rabbit/Config/Publisher.php index 05e6e11..7b2b2bc 100644 --- a/src/Rabbit/Config/Publisher.php +++ b/src/Rabbit/Config/Publisher.php @@ -6,20 +6,11 @@ class Publisher { - private const DEFAULT_ATTEMPTS = 3; - - private $exchangeName; - private $confirmSelect; - private $attempts; - public function __construct( - string $exchangeName, - bool $confirmSelect = true, - int $attempts = self::DEFAULT_ATTEMPTS + private readonly string $exchangeName, + private readonly bool $confirmSelect = true, + private readonly int $attempts = 3 ) { - $this->exchangeName = $exchangeName; - $this->confirmSelect = $confirmSelect; - $this->attempts = $attempts; } public function confirmSelect(): bool diff --git a/src/Rabbit/ConnectionContainer.php b/src/Rabbit/ConnectionContainer.php index 4f6a02b..bc85dc2 100644 --- a/src/Rabbit/ConnectionContainer.php +++ b/src/Rabbit/ConnectionContainer.php @@ -10,41 +10,21 @@ class ConnectionContainer { - private const DEFAULT_WAIT_BEFORE_RECONNECT_MICROSECONDS = 1000000; + private mixed $waitBeforeReconnectMicroseconds = 1000000; - private $host; - private $port; - private $user; - private $pass; - private $vhost; - private $sslOptions; - private $options; - private $waitBeforeReconnectMicroseconds; - - /** - * @var AbstractConnection|null - */ - private $connection; + private ?AbstractConnection $connection; public function __construct( - string $host, - string $port, - string $user, - string $pass, - string $vhost = '/', - array $sslOptions = [], - array $options = [] + private readonly string $host, + private readonly string $port, + private readonly string $user, + private readonly string $pass, + private readonly string $vhost = '/', + private readonly array $sslOptions = [], + private readonly array $options = [] ) { - $this->host = $host; - $this->port = $port; - $this->user = $user; - $this->pass = $pass; - $this->vhost = $vhost; - $this->sslOptions = $sslOptions; - $this->options = $options; - - $this->waitBeforeReconnectMicroseconds = $options['wait_before_reconnect_microseconds'] - ?? self::DEFAULT_WAIT_BEFORE_RECONNECT_MICROSECONDS; + $this->waitBeforeReconnectMicroseconds = $options['wait_before_reconnect_microseconds'] ?? + $this->waitBeforeReconnectMicroseconds; } public function __destruct() diff --git a/src/Rabbit/Consumer.php b/src/Rabbit/Consumer.php index d73304c..c67cecc 100644 --- a/src/Rabbit/Consumer.php +++ b/src/Rabbit/Consumer.php @@ -11,23 +11,14 @@ class Consumer { - private $channelContainer; - private $messageBuilder; - private $config; - private $logger; - - private $working; + private bool $working; public function __construct( - ChannelContainer $channelContainer, - MessageBuilder $messageBuilder, - Config\Consumer $config, - LoggerInterface $logger = null + private readonly ChannelContainer $channelContainer, + private readonly MessageBuilder $messageBuilder, + private readonly Config\Consumer $config, + private readonly LoggerInterface $logger = new NullLogger() ) { - $this->messageBuilder = $messageBuilder; - $this->channelContainer = $channelContainer; - $this->config = $config; - $this->logger = $logger ?? new NullLogger(); } public function consume(): void diff --git a/src/Rabbit/MessageBuilder.php b/src/Rabbit/MessageBuilder.php index 1fab401..ed99212 100644 --- a/src/Rabbit/MessageBuilder.php +++ b/src/Rabbit/MessageBuilder.php @@ -14,11 +14,10 @@ class MessageBuilder { public const EVENT_NAME = 'table_sync'; - private $publishMessageConfig; - public function __construct(Config\PublishMessage $publishMessageConfig) - { - $this->publishMessageConfig = $publishMessageConfig; + public function __construct( + private readonly Config\PublishMessage $publishMessageConfig + ) { } public function buildReceivedMessage(AMQPMessage $message): ReceivedMessage diff --git a/src/Rabbit/Publisher.php b/src/Rabbit/Publisher.php index 147ec8e..2355009 100644 --- a/src/Rabbit/Publisher.php +++ b/src/Rabbit/Publisher.php @@ -15,21 +15,12 @@ final class Publisher implements PublisherContract { - private $config; - private $connectionContainer; - private $messageBuilder; - private $logger; - public function __construct( - Config $config, - ConnectionContainer $connectionContainer, - MessageBuilder $messageBuilder, - LoggerInterface $logger = null + private readonly Config $config, + private readonly ConnectionContainer $connectionContainer, + private readonly MessageBuilder $messageBuilder, + private readonly LoggerInterface $logger = new NullLogger() ) { - $this->config = $config; - $this->connectionContainer = $connectionContainer; - $this->messageBuilder = $messageBuilder; - $this->logger = $logger ?? new NullLogger(); } public function publish(PublishMessage $message): void diff --git a/tests/unit/Logging/FormatterTest.php b/tests/unit/Logging/FormatterTest.php index 3129d12..eac7d0c 100644 --- a/tests/unit/Logging/FormatterTest.php +++ b/tests/unit/Logging/FormatterTest.php @@ -4,7 +4,10 @@ namespace Umbrellio\TableSync\Tests\Unit\Logging; +use DateTimeImmutable; use InfluxDB\Point; +use Monolog\Level; +use Monolog\LogRecord; use Umbrellio\TableSync\Messages\PublishMessage; use Umbrellio\TableSync\Monolog\Formatter\InfluxDBFormatter; use Umbrellio\TableSync\Monolog\Formatter\JsonTableSyncFormatter; @@ -38,10 +41,8 @@ public function tableSyncFormat(): void $this->assertIsArray($format); $this->assertIsArray($format['attributes']); - $format = $tableSyncFormatter->format([ - 'message' => '', - 'datetime' => '', - ]); + $record = new LogRecord(new DateTimeImmutable(), '', Level::Debug, ''); + $format = $tableSyncFormatter->format($record); $this->assertSame([ 'datetime', 'message', @@ -85,27 +86,27 @@ public function influxDbFormatter(): void public function jsonTableSyncFormat(): void { $jsonTableSyncFormatter = new JsonTableSyncFormatter(); - $format = $jsonTableSyncFormatter->format($this->getDummyRecord()); - $expected = '{"datetime":"datetime","message":"message","direction":"direction","routing":"routing_key","model":"model","event":"update","count":1}' . "\n"; + $dateTime = new DateTimeImmutable(); + $format = $jsonTableSyncFormatter->format($this->getDummyRecord($dateTime)); + $expected = '{"datetime":"' . $dateTime->format('Y-m-d\TH:i:s.uP') . + '","message":"message","direction":"direction","routing":"routing_key",' . + '"model":"model","event":"update","count":1}' . "\n"; $this->assertIsString($format); $this->assertSame($expected, $format); } - private function getDummyRecord(): array + private function getDummyRecord(DateTimeImmutable $dateTime = new DateTimeImmutable()): LogRecord { $message = new PublishMessage('model', 'event', 'routingKey', [ 'id' => 1, ]); $amqpMessage = (new MessageBuilder(new Config('appId')))->buildForPublishing($message); - - return [ - 'message' => 'message', - 'context' => [ - 'direction' => 'direction', - 'routing_key' => 'routing_key', - 'body' => $amqpMessage->getBody(), - ], - 'datetime' => 'datetime', + $context = [ + 'direction' => 'direction', + 'routing_key' => 'routing_key', + 'body' => $amqpMessage->getBody(), ]; + + return new LogRecord($dateTime, '', Level::Debug, 'message', $context); } } diff --git a/tests/unit/Messages/PublishMessageTest.php b/tests/unit/Messages/PublishMessageTest.php index 5710a40..3645429 100644 --- a/tests/unit/Messages/PublishMessageTest.php +++ b/tests/unit/Messages/PublishMessageTest.php @@ -32,7 +32,7 @@ public function detectIfDestroyed(): void $message = new PublishMessage('class', 'event', 'test_key'); $this->assertFalse($message->isDestroyed()); - $message = new PublishMessage('class', PublishMessage::EVENT_DESTROYED, 'test_key'); + $message = new PublishMessage('class', PublishMessage::EVENT_DELETED, 'test_key'); $this->assertTrue($message->isDestroyed()); } diff --git a/tests/unit/Rabbit/MessageBuilderTest.php b/tests/unit/Rabbit/MessageBuilderTest.php index eaa734e..7f8f92f 100644 --- a/tests/unit/Rabbit/MessageBuilderTest.php +++ b/tests/unit/Rabbit/MessageBuilderTest.php @@ -96,7 +96,7 @@ public function bodyEvent(): void $this->assertSame('update', $body['event']); $amqpMessage = $this->builder->buildForPublishing( - new PublishMessage('class', PublishMessage::EVENT_DESTROYED, 'test_key') + new PublishMessage('class', PublishMessage::EVENT_DELETED, 'test_key') ); $body = $this->decodedBodyFromMessage($amqpMessage);