diff --git a/.docker/compose.yaml b/.docker/compose.yaml new file mode 100644 index 0000000..55b037f --- /dev/null +++ b/.docker/compose.yaml @@ -0,0 +1,14 @@ +x-build-args: &build-args + UID: "${UID:-1000}" + GID: "${GID:-1000}" + +name: cleverage-cache-process-bundle + +services: + php: + build: + context: php + args: + <<: *build-args + volumes: + - ../:/var/www diff --git a/.docker/php/Dockerfile b/.docker/php/Dockerfile new file mode 100644 index 0000000..f98c3ba --- /dev/null +++ b/.docker/php/Dockerfile @@ -0,0 +1,29 @@ +FROM php:8.2-fpm-alpine + +ARG UID +ARG GID + +RUN mv "$PHP_INI_DIR/php.ini-development" "$PHP_INI_DIR/php.ini" +COPY /conf.d/ "$PHP_INI_DIR/conf.d/" + +RUN apk update && apk add \ + tzdata \ + shadow \ + nano \ + bash \ + icu-dev \ + && docker-php-ext-configure intl \ + && docker-php-ext-install intl opcache \ + && docker-php-ext-enable opcache + +RUN ln -s /usr/share/zoneinfo/Europe/Paris /etc/localtime \ + && sed -i "s/^;date.timezone =.*/date.timezone = Europe\/Paris/" $PHP_INI_DIR/php.ini + +COPY --from=composer:2 /usr/bin/composer /usr/bin/composer + +RUN usermod -u $UID www-data \ + && groupmod -g $GID www-data + +USER www-data:www-data + +WORKDIR /var/www diff --git a/.docker/php/conf.d/dev.ini b/.docker/php/conf.d/dev.ini new file mode 100644 index 0000000..2a141be --- /dev/null +++ b/.docker/php/conf.d/dev.ini @@ -0,0 +1,5 @@ +display_errors = 1 +error_reporting = E_ALL + +opcache.validate_timestamps = 1 +opcache.revalidate_freq = 0 diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..7711713 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,14 @@ +## Description + + + +## Requirements + +* Documentation updates + - [ ] Reference + - [ ] Changelog +* [ ] Unit tests + +## Breaking changes + + diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 0000000..58db37d --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,14 @@ +## Description + + + +## Requirements + +* Documentation updates + - [ ] Reference + - [ ] Changelog +* [ ] Unit tests + +## Breaking changes + + diff --git a/.github/workflows/notifications.yml b/.github/workflows/notifications.yml new file mode 100644 index 0000000..44b80b9 --- /dev/null +++ b/.github/workflows/notifications.yml @@ -0,0 +1,23 @@ +name: Rocket chat notifications + +# Controls when the action will run. +on: + push: + tags: + - '*' + +jobs: + notification: + runs-on: ubuntu-latest + + steps: + - name: Get the tag short reference + id: get_tag + run: echo "TAG=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_OUTPUT + + - name: Rocket.Chat Notification + uses: madalozzo/Rocket.Chat.GitHub.Action.Notification@master + with: + type: success + job_name: "[cleverage/cache-process-bundle](https://github.com/cleverage/cache-process-bundle) : ${{ steps.get_tag.outputs.TAG }} has been released" + url: ${{ secrets.CLEVER_AGE_ROCKET_CHAT_WEBOOK_URL }} diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml new file mode 100644 index 0000000..9f1580f --- /dev/null +++ b/.github/workflows/quality.yml @@ -0,0 +1,62 @@ +name: Quality + +on: + push: + branches: + - main + pull_request: + +permissions: + contents: read + +jobs: + phpstan: + name: PHPStan + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install PHP with extensions + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + coverage: none + tools: composer:v2 + - name: Install Composer dependencies (locked) + uses: ramsey/composer-install@v3 + - name: PHPStan + run: vendor/bin/phpstan --no-progress --memory-limit=1G analyse --error-format=github + + php-cs-fixer: + name: PHP-CS-Fixer + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install PHP with extensions + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + coverage: none + tools: composer:v2 + - name: Install Composer dependencies (locked) + uses: ramsey/composer-install@v3 + - name: PHP-CS-Fixer + run: vendor/bin/php-cs-fixer fix --diff --dry-run --show-progress=none + + rector: + name: Rector + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Install PHP with extensions + uses: shivammathur/setup-php@v2 + with: + php-version: '8.2' + coverage: none + tools: composer:v2 + - name: Install Composer dependencies (locked) + uses: ramsey/composer-install@v3 + - name: Rector + run: vendor/bin/rector --no-progress-bar --dry-run diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..2d7e7a4 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,74 @@ +name: Test + +on: + push: + branches: + - main + pull_request: + +permissions: + contents: read + +jobs: + test: + name: PHP ${{ matrix.php-version }} + ${{ matrix.dependencies }} + ${{ matrix.variant }} + runs-on: ubuntu-latest + continue-on-error: ${{ matrix.allowed-to-fail }} + env: + SYMFONY_REQUIRE: ${{matrix.symfony-require}} + + strategy: + matrix: + php-version: + - '8.2' + - '8.3' + dependencies: [highest] + allowed-to-fail: [false] + symfony-require: [''] + variant: [normal] + include: + - php-version: '8.2' + dependencies: highest + allowed-to-fail: false + symfony-require: 6.4.* + variant: symfony/symfony:"6.4.*" + - php-version: '8.2' + dependencies: highest + allowed-to-fail: false + symfony-require: 7.1.* + variant: symfony/symfony:"7.1.*" + - php-version: '8.3' + dependencies: highest + allowed-to-fail: false + symfony-require: 6.4.* + variant: symfony/symfony:"6.4.*" + - php-version: '8.3' + dependencies: highest + allowed-to-fail: false + symfony-require: 7.1.* + variant: symfony/symfony:"7.1.*" + + steps: + - name: Checkout + uses: actions/checkout@v4 + - name: Install PHP with extensions + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php-version }} + coverage: pcov + tools: composer:v2, flex + - name: Add PHPUnit matcher + run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + - name: Install variant + if: matrix.variant != 'normal' && !startsWith(matrix.variant, 'symfony/symfony') + run: composer require ${{ matrix.variant }} --no-update + - name: Install Composer dependencies (${{ matrix.dependencies }}) + uses: ramsey/composer-install@v3 + with: + dependency-versions: ${{ matrix.dependencies }} + - name: Run Tests with coverage + run: vendor/bin/phpunit -c phpunit.xml.dist --coverage-clover build/logs/clover.xml + #- name: Send coverage to Codecov + # uses: codecov/codecov-action@v4 + # with: + # files: build/logs/clover.xml diff --git a/.gitignore b/.gitignore index ff72e2d..ca08796 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,9 @@ /composer.lock /vendor +.env +.idea +/phpunit.xml +.phpunit.result.cache +.phpunit.cache +.php-cs-fixer.cache +coverage-report diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php new file mode 100644 index 0000000..68f8bcf --- /dev/null +++ b/.php-cs-fixer.dist.php @@ -0,0 +1,46 @@ +setRules([ + '@PHP71Migration' => true, + '@PHP82Migration' => true, + '@PHPUnit75Migration:risky' => true, + '@Symfony' => true, + '@Symfony:risky' => true, + 'protected_to_private' => false, + 'native_constant_invocation' => ['strict' => false], + 'header_comment' => ['header' => $fileHeaderComment], + 'modernize_strpos' => true, + 'get_class_to_class_keyword' => true, + ]) + ->setRiskyAllowed(true) + ->setFinder( + (new PhpCsFixer\Finder()) + ->in(__DIR__.'/src') + ->in(__DIR__.'/tests') + ->append([__FILE__]) + ) + ->setCacheFile('.php-cs-fixer.cache') +; diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..487786b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,21 @@ +v1.0.0 +------ + +* Initial stable release + +## BC breaks + +* [#3](https://github.com/cleverage/cache-process-bundle/issues/3) Bump dependency "cleverage/process-bundle": "^4.0" +* [#5](https://github.com/cleverage/cache-process-bundle/issues/5) Update services according to Symfony best practices. Services should not use autowiring or autoconfiguration. Instead, all services should be defined explicitly. + Services must be prefixed with the bundle alias instead of using fully qualified class names => `cleverage_cache_process` +* [#1](https://github.com/cleverage/cache-process-bundle/issues/1) Rework Tasks & Transfomers using AdapterRegistry + +### Changes + +* [#4](https://github.com/cleverage/cache-process-bundle/issues/4) Add Makefile & .docker for local standalone usage +* [#4](https://github.com/cleverage/cache-process-bundle/issues/4) Add rector, phpstan & php-cs-fixer configurations & apply it + +v0.3 +------ + +* Legacy release diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..8222397 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,52 @@ +Contributing +============ + +First of all, **thank you** for contributing, **you are awesome**! + +Here are a few rules to follow in order to ease code reviews, and discussions before +maintainers accept and merge your work. + +You MUST run the quality & test suites. + +You SHOULD write (or update) unit tests. + +You SHOULD write documentation. + +Please, write [commit messages that make sense](https://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html), +and [rebase your branch](https://git-scm.com/book/en/v2/Git-Branching-Rebasing) before submitting your Pull Request. + +One may ask you to [squash your commits](https://gitready.com/advanced/2009/02/10/squashing-commits-with-rebase.html) +too. This is used to "clean" your Pull Request before merging it (we don't want +commits such as `fix tests`, `fix 2`, `fix 3`, etc.). + +Thank you! + +## Running the quality & test suites + +Tests suite uses Docker environments in order to be idempotent to OS's. More than this +PHP version is written inside the Dockerfile; this assures to test the bundle with +the same resources. No need to have PHP installed. + +You only need Docker set it up. + +To allow testing environments more smooth we implemented **Makefile**. +You have two commands available: + +```bash +make quality +``` + +```bash +make tests +``` + +## Deprecations notices + +When a feature should be deprecated, or when you have a breaking change for a future version, please : +* [Fill an issue](https://github.com/cleverage/cache-process-bundl/issues/new) +* Add TODO comments with the following format: `@TODO deprecated v2.0` +* Trigger a deprecation error: `@trigger_error('This feature will be deprecated in v2.0', E_USER_DEPRECATED);` + +You can check which deprecation notice is triggered in tests +* `make bash` +* `SYMFONY_DEPRECATIONS_HELPER=0 ./vendor/bin/phpunit` diff --git a/CleverAgeCacheProcessBundle.php b/CleverAgeCacheProcessBundle.php deleted file mode 100644 index 63d0cfe..0000000 --- a/CleverAgeCacheProcessBundle.php +++ /dev/null @@ -1,24 +0,0 @@ - - * @author Vincent Chalnot - * @author Madeline Veyrenc - */ -class CleverAgeCacheProcessBundle extends Bundle -{ -} diff --git a/DependencyInjection/CleverAgeCacheProcessExtension.php b/DependencyInjection/CleverAgeCacheProcessExtension.php deleted file mode 100644 index 3e76c47..0000000 --- a/DependencyInjection/CleverAgeCacheProcessExtension.php +++ /dev/null @@ -1,26 +0,0 @@ - - * @author Vincent Chalnot - * @author Madeline Veyrenc - */ -class CleverAgeCacheProcessExtension extends SidusBaseExtension -{ -} diff --git a/DependencyInjection/Compiler/CachePoolPass.php b/DependencyInjection/Compiler/CachePoolPass.php deleted file mode 100644 index 31797a7..0000000 --- a/DependencyInjection/Compiler/CachePoolPass.php +++ /dev/null @@ -1,55 +0,0 @@ - - */ -class CachePoolPass implements CompilerPassInterface -{ - /** - * Inject tagged services into defined registry - * - * @param ContainerBuilder $container - * - * @throws InvalidArgumentException - * @throws \UnexpectedValueException - * @throws ServiceNotFoundException - * @throws \Exception - * @api - * - */ - public function process(ContainerBuilder $container) - { - $name = 'cache.app.cleverage_process'; - $pool = [ - 'adapter' => 'cache.app', - 'public' => true, - ]; - $definition = new ChildDefinition($pool['adapter']); - $container->registerAliasForArgument($name, CacheInterface::class); - $container->registerAliasForArgument($name, CacheItemPoolInterface::class); - $definition->setPublic($pool['public']); - - $definition->addTag('cache.pool'); - $container->setDefinition($name, $definition); - } -} diff --git a/LICENSE b/LICENSE index fdc6131..045d824 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2015-2019 Clever-Age +Copyright (c) Clever-Age Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0a58e32 --- /dev/null +++ b/Makefile @@ -0,0 +1,54 @@ +.ONESHELL: +SHELL := /bin/bash + +DOCKER_RUN_PHP = docker compose -f .docker/compose.yaml run --rm php "bash" "-c" +DOCKER_COMPOSE = docker compose -f .docker/compose.yaml + +start: upd #[Global] Start application + +src/vendor: #[Composer] install dependencies + $(DOCKER_RUN_PHP) "composer install --no-interaction" + +upd: #[Docker] Start containers detached + touch .docker/.env + make src/vendor + $(DOCKER_COMPOSE) up --remove-orphans --detach + +up: #[Docker] Start containers + touch .docker/.env + make src/vendor + $(DOCKER_COMPOSE) up --remove-orphans + +stop: #[Docker] Down containers + $(DOCKER_COMPOSE) stop + +down: #[Docker] Down containers + $(DOCKER_COMPOSE) down + +build: #[Docker] Build containers + $(DOCKER_COMPOSE) build + +ps: # [Docker] Show running containers + $(DOCKER_COMPOSE) ps + +bash: #[Docker] Connect to php container with current host user + $(DOCKER_COMPOSE) exec php bash + +logs: #[Docker] Show logs + $(DOCKER_COMPOSE) logs -f + +quality: phpstan php-cs-fixer rector #[Quality] Run all quality checks + +phpstan: #[Quality] Run PHPStan + $(DOCKER_RUN_PHP) "vendor/bin/phpstan --no-progress --memory-limit=1G analyse" + +php-cs-fixer: #[Quality] Run PHP-CS-Fixer + $(DOCKER_RUN_PHP) "vendor/bin/php-cs-fixer fix --diff --verbose" + +rector: #[Quality] Run Rector + $(DOCKER_RUN_PHP) "vendor/bin/rector" + +tests: phpunit #[Tests] Run all tests + +phpunit: #[Tests] Run PHPUnit + $(DOCKER_RUN_PHP) "vendor/bin/phpunit" diff --git a/README.md b/README.md index d2bb616..cb5b76d 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,22 @@ CleverAge/CacheProcessBundle ======================= -See process bundle documentation +This bundle is a part of the [CleverAge/ProcessBundle](https://github.com/cleverage/process-bundle) project. +It provides [Cache](https://symfony.com/doc/current/components/cache.html) integration on Process bundle. -## Help needed - -This bundle is a mess, it doesn't require the proper dependencies, it uses missing methods (transformValue), there is a -general lack of comments and annotations and it needs to be properly migrated to PHP7.1+. - -Also we need to check if tests are ok. +Compatible with [Symfony stable version and latest Long-Term Support (LTS) release](https://symfony.com/releases). ## Documentation -Contains tasks and transformers to handle cache. - -Activation ----------- - -Activated if cache pool `cleverage_process` is defined. - -Task reference --------------- - -* **Service**: `CleverAge\ProcessBundle\Transformer\ArrayFilterTransformer` -* **Transformer code**: `array_filter` - -Accepted inputs ---------------- - -`array` or `\Iterable` +For usage documentation, see: +[docs/index.md](docs/index.md) -Possible outputs ----------------- +## Support & Contribution -`array` containing only filtered data +For general support and questions, please use [Github](https://github.com/cleverage/cache-process-bundle/issues). +If you think you found a bug or you have a feature idea to propose, feel free to open an issue after looking at the [contributing](CONTRIBUTING.md) guide. -Options -------- +## License -| Code | Type | Required | Default | Description | -| ---- | ---- | :------: | ------- | ----------- | -| `condition` | `array` | | `[]` | See [ConditionTrait](TODO) | -____ +This bundle is under the MIT license. +For the whole copyright, see the [LICENSE](LICENSE) file distributed with this source code. diff --git a/Resources/config/services/task.yml b/Resources/config/services/task.yml deleted file mode 100644 index 820c55f..0000000 --- a/Resources/config/services/task.yml +++ /dev/null @@ -1,10 +0,0 @@ -services: - CleverAge\CacheProcessBundle\Task\: - resource: '../../../Task/*' - autowire: true - public: true - shared: false - arguments: - $cache: '@cache.app' - tags: - - { name: monolog.logger, channel: cleverage_process_task } diff --git a/Resources/config/services/transformer.yml b/Resources/config/services/transformer.yml deleted file mode 100644 index 317edf0..0000000 --- a/Resources/config/services/transformer.yml +++ /dev/null @@ -1,10 +0,0 @@ -services: - CleverAge\CacheProcessBundle\Transformer\: - resource: '../../../Transformer/*' - autowire: true - public: false - arguments: - $cache: '@cache.app' - tags: - - { name: cleverage.transformer } - - { name: monolog.logger, channel: cleverage_process_transformer } diff --git a/Task/AbstractCacheTask.php b/Task/AbstractCacheTask.php deleted file mode 100644 index 4f7b98f..0000000 --- a/Task/AbstractCacheTask.php +++ /dev/null @@ -1,126 +0,0 @@ - - */ -abstract class AbstractCacheTask extends AbstractConfigurableTask -{ - use TransformerTrait; - - /** @var CacheItemPoolInterface */ - private $cache; - - /** - * SetterTask constructor. - * - * @param LoggerInterface $logger - * @param PropertyAccessorInterface $accessor - * @param CacheItemPoolInterface $cache - * @param TransformerRegistry $transformerRegistry - */ - public function __construct( - LoggerInterface $logger, - PropertyAccessorInterface $accessor, - CacheItemPoolInterface $cache, - TransformerRegistry $transformerRegistry - ) { - $this->logger = $logger; - $this->accessor = $accessor; - $this->cache = $cache; - $this->transformerRegistry = $transformerRegistry; - } - - /** - * @return CacheItemPoolInterface - */ - public function getCache(): CacheItemPoolInterface - { - return $this->cache; - } - - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ - protected function configureOptions(OptionsResolver $resolver) - { - $resolver->setRequired( - [ - 'key', - ] - ); - $resolver->setAllowedTypes('key', ['array', 'null']); - - /** @noinspection PhpUnusedParameterInspection */ - $resolver->setNormalizer( - 'key', - function (Options $options, $value) { - $mappingResolver = new OptionsResolver(); - $this->configureMappingOptions($mappingResolver); - - return $mappingResolver->resolve( - $value ?? [] - ); - } - ); - } - - /** - * @param OptionsResolver $resolver - * - * @throws ExceptionInterface - */ - protected function configureMappingOptions(OptionsResolver $resolver) - { - $resolver->setDefaults( - [ - 'code' => null, // Source property - 'constant' => null, - ] - ); - $resolver->setAllowedTypes('code', ['NULL', 'string', 'array']); - - $this->configureTransformersOptions($resolver); - } - - /** - * @param ProcessState $state - * - * @throws ExceptionInterface - * @return string - * - */ - protected function getKeyCache(ProcessState $state) - { - $options = $this->getOptions($state); - - return $this->transformValue($state->getInput(), $options['key']); - } -} diff --git a/Task/DeleterTask.php b/Task/DeleterTask.php deleted file mode 100644 index 2438724..0000000 --- a/Task/DeleterTask.php +++ /dev/null @@ -1,39 +0,0 @@ - - */ -class DeleterTask extends AbstractCacheTask -{ - /** - * @param ProcessState $state - * - * @throws InvalidArgumentException - * @throws ExceptionInterface - */ - public function execute(ProcessState $state) - { - $keyValue = $this->getKeyCache($state); - $input = $state->getInput(); - - $this->getCache()->deleteItem($keyValue); - - $state->setOutput($input); - } -} diff --git a/Task/GetterTask.php b/Task/GetterTask.php deleted file mode 100644 index f40f89e..0000000 --- a/Task/GetterTask.php +++ /dev/null @@ -1,42 +0,0 @@ - - */ -class GetterTask extends AbstractCacheTask -{ - /** - * @param ProcessState $state - * - * @throws InvalidArgumentException - * @throws ExceptionInterface - */ - public function execute(ProcessState $state) - { - $keyValue = $this->getKeyCache($state); - $cacheItem = $this->getCache()->getItem($keyValue); - - if (!$cacheItem->isHit()) { - $state->setErrorOutput($state->getInput()); - $state->setSkipped(true); - } - - $state->setOutput($cacheItem->get()); - } -} diff --git a/Task/SetterTask.php b/Task/SetterTask.php deleted file mode 100644 index e2f4b31..0000000 --- a/Task/SetterTask.php +++ /dev/null @@ -1,74 +0,0 @@ - - */ -class SetterTask extends AbstractCacheTask -{ - /** - * @param ProcessState $state - * - * @throws InvalidArgumentException - * @throws ExceptionInterface - */ - public function execute(ProcessState $state) - { - $keyValue = $this->getKeyCache($state); - $input = $state->getInput(); - - $cacheItem = $this->getCache()->getItem($keyValue); - $cachedValue = $this->transformValue($input, $this->getOption($state, 'value')); - $cacheItem->set($cachedValue); - $this->getCache()->save($cacheItem); - - $state->setOutput($input); - } - - /** - * {@inheritdoc} - */ - protected function configureOptions(OptionsResolver $resolver) - { - parent::configureOptions($resolver); - - $resolver->setRequired( - [ - 'value', - ] - ); - $resolver->setAllowedTypes('value', ['array', 'null']); - - /** @noinspection PhpUnusedParameterInspection */ - $resolver->setNormalizer( - 'value', - function (Options $options, $value) { - $mappingResolver = new OptionsResolver(); - $this->configureMappingOptions($mappingResolver); - - return $mappingResolver->resolve( - $value ?? [] - ); - } - ); - - return $resolver; - } -} diff --git a/Transformer/AbstractCacheTransformer.php b/Transformer/AbstractCacheTransformer.php deleted file mode 100644 index ccf7d87..0000000 --- a/Transformer/AbstractCacheTransformer.php +++ /dev/null @@ -1,126 +0,0 @@ - - */ -abstract class AbstractCacheTransformer implements ConfigurableTransformerInterface -{ - use TransformerTrait; - - /** @var CacheItemPoolInterface */ - private $cache; - - /** - * SetterTask constructor. - * - * @param LoggerInterface $logger - * @param PropertyAccessorInterface $accessor - * @param CacheItemPoolInterface $cache - * @param TransformerRegistry $transformerRegistry - */ - public function __construct( - LoggerInterface $logger, - PropertyAccessorInterface $accessor, - CacheItemPoolInterface $cache, - TransformerRegistry $transformerRegistry - ) { - $this->logger = $logger; - $this->accessor = $accessor; - $this->cache = $cache; - $this->transformerRegistry = $transformerRegistry; - } - - /** - * @return CacheItemPoolInterface - */ - public function getCache(): CacheItemPoolInterface - { - return $this->cache; - } - - /** - * @param OptionsResolver $resolver - * - * @throws AccessException - * @throws UndefinedOptionsException - */ - public function configureOptions(OptionsResolver $resolver) - { - $resolver->setRequired( - [ - 'key', - ] - ); - $resolver->setAllowedTypes('key', ['array', 'null']); - - /** @noinspection PhpUnusedParameterInspection */ - $resolver->setNormalizer( - 'key', - function (Options $options, $value) { - $mappingResolver = new OptionsResolver(); - $this->configureMappingOptions($mappingResolver); - - return $mappingResolver->resolve( - $value ?? [] - ); - } - ); - } - - /** - * @param OptionsResolver $resolver - * - * @throws ExceptionInterface - */ - protected function configureMappingOptions(OptionsResolver $resolver) - { - $resolver->setDefaults( - [ - 'code' => null, // Source property - 'constant' => null, - ] - ); - $resolver->setAllowedTypes('code', ['NULL', 'string', 'array']); - - $this->configureTransformersOptions($resolver); - } - - /** - * @param mixed $value - * @param array $options - * - * @return string - */ - protected function getKeyCache($value, array $options = []) - { - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - $options = $resolver->resolve($options); - - return $this->transformValue($value, $options['key']); - } -} diff --git a/Transformer/DeleterTransformer.php b/Transformer/DeleterTransformer.php deleted file mode 100644 index 8ba9801..0000000 --- a/Transformer/DeleterTransformer.php +++ /dev/null @@ -1,44 +0,0 @@ - - */ -class DeleterTransformer extends AbstractCacheTransformer -{ - /** - * {@inheritDoc} - * - * @throws \UnexpectedValueException - * @throws InvalidArgumentException - */ - public function transform($value, array $options = []) - { - $keyValue = $this->getKeyCache($value, $options); - - $this->getCache()->deleteItem($keyValue); - - return $value; - } - - /** - * {@inheritDoc} - */ - public function getCode() - { - return 'cache_deleter'; - } -} diff --git a/Transformer/GetterTransformer.php b/Transformer/GetterTransformer.php deleted file mode 100644 index d7e0855..0000000 --- a/Transformer/GetterTransformer.php +++ /dev/null @@ -1,68 +0,0 @@ - - */ -class GetterTransformer extends AbstractCacheTransformer -{ - /** - * {@inheritDoc} - */ - public function configureOptions(OptionsResolver $resolver) - { - parent::configureOptions($resolver); - - $resolver->setDefaults( - [ - 'ignore_not_hit' => false, - ] - ); - $resolver->setAllowedTypes('ignore_not_hit', ['boolean']); - } - - /** - * {@inheritDoc} - * - * @throws \UnexpectedValueException - * @throws InvalidArgumentException - */ - public function transform($value, array $options = []) - { - $keyValue = $this->getKeyCache($value, $options); - $cacheItem = $this->getCache()->getItem($keyValue); - - if (!$cacheItem->isHit()) { - if ($options['ignore_not_hit']) { - return null; - } - - throw new TransformerException($keyValue, 0, 'Cache not hit'); - } - - return $cacheItem->get(); - } - - /** - * {@inheritDoc} - */ - public function getCode() - { - return 'cache_getter'; - } -} diff --git a/Transformer/SetterTransformer.php b/Transformer/SetterTransformer.php deleted file mode 100644 index b825f10..0000000 --- a/Transformer/SetterTransformer.php +++ /dev/null @@ -1,84 +0,0 @@ - - */ -class SetterTransformer extends AbstractCacheTransformer -{ - /** - * {@inheritDoc} - * - * @throws \UnexpectedValueException - * @throws InvalidArgumentException - */ - public function transform($value, array $options = []) - { - $keyValue = $this->getKeyCache($value, $options); - - $cacheItem = $this->getCache()->getItem($keyValue); - $resolver = new OptionsResolver(); - $this->configureOptions($resolver); - $options = $resolver->resolve($options); - $cachedValue = $this->transformValue($value, $options['value']); - $cacheItem->set($cachedValue); - $this->getCache()->save($cacheItem); - - return $value; - } - - /** - * {@inheritDoc} - */ - public function getCode() - { - return 'cache_setter'; - } - - /** - * {@inheritDoc} - */ - public function configureOptions(OptionsResolver $resolver) - { - parent::configureOptions($resolver); - - $resolver->setRequired( - [ - 'value', - ] - ); - $resolver->setAllowedTypes('value', ['array', 'null']); - - /** @noinspection PhpUnusedParameterInspection */ - $resolver->setNormalizer( - 'value', - function (Options $options, $value) { - $mappingResolver = new OptionsResolver(); - $this->configureMappingOptions($mappingResolver); - - return $mappingResolver->resolve( - $value ?? [] - ); - } - ); - - return $resolver; - } - - -} diff --git a/composer.json b/composer.json index a455880..e31aa57 100644 --- a/composer.json +++ b/composer.json @@ -15,32 +15,42 @@ "license": "MIT", "authors": [ { - "name": "Vincent Chalnot", - "email": "vchalnot@clever-age.com", - "homepage": "http://chalnot.fr", + "name": "Nicolas Joubert", + "email": "njoubert@clever-age.com", "role": "Lead Developer" - }, - { - "name": "Valentin Clavreul", - "email": "vclavreul@clever-age.com", - "role": "Developer" - }, - { - "name": "Madeline Veyrenc", - "email": "mveyrenc@clever-age.com", - "homepage": "https://github.com/mveyrenc", - "role": "Developer" } ], "autoload": { "psr-4": { - "CleverAge\\CacheProcessBundle\\": "" + "CleverAge\\CacheProcessBundle\\": "src/" + } + }, + "autoload-dev": { + "psr-4": { + "CleverAge\\CacheProcessBundle\\Tests\\": "tests/" } }, "require": { - "cleverage/process-bundle": "3.*|dev-v3.0-dev" + "php": ">=8.1", + "cleverage/process-bundle": "^4.0", + "symfony/cache": "^6.4|^7.1" }, "require-dev": { - "phpunit/phpunit": "~6.4" + "friendsofphp/php-cs-fixer": "*", + "phpstan/extension-installer": "*", + "phpstan/phpstan": "*", + "phpstan/phpstan-symfony": "*", + "phpunit/phpunit": "<10.0", + "rector/rector": "*", + "roave/security-advisories": "dev-latest", + "symfony/test-pack": "^1.1" + }, + "config": { + "allow-plugins": { + "phpstan/extension-installer": true, + "symfony/flex": true, + "symfony/runtime": true + }, + "sort-packages": true } } diff --git a/config/services/registry.yaml b/config/services/registry.yaml new file mode 100644 index 0000000..2de9a05 --- /dev/null +++ b/config/services/registry.yaml @@ -0,0 +1,4 @@ +services: + cleverage_cache_process.registry.adapter: + class: CleverAge\CacheProcessBundle\Registry\AdapterRegistry + public: false diff --git a/config/services/task.yaml b/config/services/task.yaml new file mode 100644 index 0000000..dd3b621 --- /dev/null +++ b/config/services/task.yaml @@ -0,0 +1,20 @@ +services: + cleverage_cache_process.task.get: + class: CleverAge\CacheProcessBundle\Task\GetTask + public: false + shared: false + arguments: + - '@cleverage_cache_process.registry.adapter' + CleverAge\CacheProcessBundle\Task\GetTask: + alias: cleverage_cache_process.task.get + public: true + + cleverage_cache_process.task.set: + class: CleverAge\CacheProcessBundle\Task\SetTask + public: false + shared: false + arguments: + - '@cleverage_cache_process.registry.adapter' + CleverAge\CacheProcessBundle\Task\SetTask: + alias: cleverage_cache_process.task.set + public: true diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..8f4162a --- /dev/null +++ b/docs/index.md @@ -0,0 +1,27 @@ +## Prerequisite + +CleverAge/ProcessBundle must be [installed](https://github.com/cleverage/process-bundle/blob/main/docs/01-quick_start.md#installation. + +## Installation + +Make sure Composer is installed globally, as explained in the [installation chapter](https://getcomposer.org/doc/00-intro.md) +of the Composer documentation. + +Open a command console, enter your project directory and install it using composer: + +```bash +composer require cleverage/cache-process-bundle +``` + +Remember to add the following line to config/bundles.php (not required if Symfony Flex is used) + +```php +CleverAge\CacheProcessBundle\CleverAgeCacheProcessBundle::class => ['all' => true], +``` + +## Reference + +- [Adapter](reference/adapter.md) +- Tasks + - [GetTask](reference/tasks/get_task.md) + - [SetTask](reference/tasks/set_task.md) diff --git a/docs/reference/adapter.md b/docs/reference/adapter.md new file mode 100644 index 0000000..a06400c --- /dev/null +++ b/docs/reference/adapter.md @@ -0,0 +1,48 @@ +Adapter +=============== + +Create cache adapter. + +Reference +-------------- + +* **Adapter Service Interface**: `CleverAge\CacheProcessBundle\Adapter\AdapterInterface` + +Options +------- + +| Code | Type | Required | Default | Description | +|-----------|----------|:--------:|---------|------------------------------------------------------------| +| `code` | `string` | **X** | | Service identifier, used by Task adapter option | +| `adapter` | `string` | **X** | | `Symfony\Component\Cache\Adapter\AdapterInterface` service | + +Examples +-------- + +```php + + + + + tests + + + + + + src + + + diff --git a/rector.php b/rector.php new file mode 100644 index 0000000..72a2408 --- /dev/null +++ b/rector.php @@ -0,0 +1,30 @@ +withPhpVersion(PhpVersion::PHP_82) + ->withPaths([ + __DIR__.'/src', + __DIR__.'/tests', + ]) + ->withPhpSets(php82: true) + // here we can define, what prepared sets of rules will be applied + ->withPreparedSets( + deadCode: true, + codeQuality: true + ) + ->withSets([ + LevelSetList::UP_TO_PHP_82, + SymfonySetList::SYMFONY_64, + SymfonySetList::SYMFONY_71, + SymfonySetList::SYMFONY_CODE_QUALITY, + SymfonySetList::SYMFONY_CONSTRUCTOR_INJECTION, + SymfonySetList::ANNOTATIONS_TO_ATTRIBUTES, + ]) +; diff --git a/src/Adapter/Adapter.php b/src/Adapter/Adapter.php new file mode 100644 index 0000000..4681375 --- /dev/null +++ b/src/Adapter/Adapter.php @@ -0,0 +1,76 @@ +code; + } + + public function getItem(mixed $key): CacheItem + { + return $this->adapter->getItem($key); + } + + public function getItems(array $keys = []): iterable + { + return $this->adapter->getItems($keys); + } + + public function clear(string $prefix = ''): bool + { + return $this->adapter->clear($prefix); + } + + public function hasItem(string $key): bool + { + return $this->adapter->hasItem($key); + } + + public function deleteItem(string $key): bool + { + return $this->adapter->deleteItem($key); + } + + public function deleteItems(array $keys): bool + { + return $this->adapter->deleteItems($keys); + } + + public function save(CacheItemInterface $item): bool + { + return $this->adapter->save($item); + } + + public function saveDeferred(CacheItemInterface $item): bool + { + return $this->adapter->saveDeferred($item); + } + + public function commit(): bool + { + return $this->adapter->commit(); + } +} diff --git a/src/Adapter/AdapterInterface.php b/src/Adapter/AdapterInterface.php new file mode 100644 index 0000000..d55c0c1 --- /dev/null +++ b/src/Adapter/AdapterInterface.php @@ -0,0 +1,22 @@ +addCompilerPass( + new RegistryCompilerPass( + 'cleverage_cache_process.registry.adapter', + 'cleverage.cache.adapter', + 'addAdapter' + ) + ); + } + + public function getPath(): string + { + return \dirname(__DIR__); + } +} diff --git a/src/DependencyInjection/CleverAgeCacheProcessExtension.php b/src/DependencyInjection/CleverAgeCacheProcessExtension.php new file mode 100644 index 0000000..072d55a --- /dev/null +++ b/src/DependencyInjection/CleverAgeCacheProcessExtension.php @@ -0,0 +1,47 @@ +findServices($container, __DIR__.'/../../config/services'); + } + + /** + * Recursively import config files into container. + */ + protected function findServices(ContainerBuilder $container, string $path, string $extension = 'yaml'): void + { + $finder = new Finder(); + $finder->in($path) + ->name('*.'.$extension)->files(); + $loader = new YamlFileLoader($container, new FileLocator($path)); + foreach ($finder as $file) { + $loader->load($file->getFilename()); + } + } +} diff --git a/src/Exception/MissingAdapterException.php b/src/Exception/MissingAdapterException.php new file mode 100644 index 0000000..2354fec --- /dev/null +++ b/src/Exception/MissingAdapterException.php @@ -0,0 +1,21 @@ +getCode(), $this->adapters)) { + throw new \UnexpectedValueException("Adapter {$adapter->getCode()} is already defined"); + } + $this->adapters[$adapter->getCode()] = $adapter; + } + + /** + * @throws MissingAdapterException + */ + public function getAdapter(string $code): AdapterInterface + { + if (!\array_key_exists($code, $this->adapters)) { + throw new MissingAdapterException("Adapter {$code} is missing"); + } + + return $this->adapters[$code]; + } +} diff --git a/src/Task/AbstractCacheTask.php b/src/Task/AbstractCacheTask.php new file mode 100644 index 0000000..8a777d4 --- /dev/null +++ b/src/Task/AbstractCacheTask.php @@ -0,0 +1,54 @@ +setRequired(['adapter', 'key']); + + $resolver->setAllowedTypes('adapter', ['string']); + $resolver->setAllowedTypes('key', ['string']); + } + + /** + * @return array + */ + protected function getMergedOptions(ProcessState $state): array + { + /** @var array $options */ + $options = $this->getOptions($state); + + /** @var array $input */ + $input = $state->getInput() ?: []; + + return array_merge($options, $input); + } +} diff --git a/src/Task/GetTask.php b/src/Task/GetTask.php new file mode 100644 index 0000000..36ff51d --- /dev/null +++ b/src/Task/GetTask.php @@ -0,0 +1,38 @@ +getMergedOptions($state); + + $cache = $this->registry->getAdapter($mergedOptions['adapter']); + + $state->setOutput($cache->getItem($mergedOptions['key'])->get()); + } +} diff --git a/src/Task/SetTask.php b/src/Task/SetTask.php new file mode 100644 index 0000000..797bf5a --- /dev/null +++ b/src/Task/SetTask.php @@ -0,0 +1,55 @@ +getMergedOptions($state); + + $cache = $this->registry->getAdapter($mergedOptions['adapter']); + + $item = $cache->getItem($mergedOptions['key'])->set($mergedOptions['value']); + + $cache->save($item); + } + + /** + * @throws UndefinedOptionsException + * @throws AccessException + */ + protected function configureOptions(OptionsResolver $resolver): void + { + parent::configureOptions($resolver); + + $resolver->setRequired(['value']); + } +} diff --git a/Tests/Task/DeleterTaskTest.php b/test.old/Task/DeleterTaskTest.php similarity index 98% rename from Tests/Task/DeleterTaskTest.php rename to test.old/Task/DeleterTaskTest.php index 5024b23..61884fe 100644 --- a/Tests/Task/DeleterTaskTest.php +++ b/test.old/Task/DeleterTaskTest.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\CacheProcessBundle\Tests\Task; +namespace CleverAge\CacheProcessBundle\tests\Task; use CleverAge\ProcessBundle\Tests\AbstractProcessTest; use Psr\Cache\CacheItemPoolInterface; diff --git a/Tests/Task/GetterTaskTest.php b/test.old/Task/GetterTaskTest.php similarity index 98% rename from Tests/Task/GetterTaskTest.php rename to test.old/Task/GetterTaskTest.php index d48858d..ad1a2e8 100644 --- a/Tests/Task/GetterTaskTest.php +++ b/test.old/Task/GetterTaskTest.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\CacheProcessBundle\Tests\Task; +namespace CleverAge\CacheProcessBundle\tests\Task; use CleverAge\ProcessBundle\Tests\AbstractProcessTest; use Psr\Cache\CacheItemPoolInterface; diff --git a/Tests/Task/SetterTaskTest.php b/test.old/Task/SetterTaskTest.php similarity index 98% rename from Tests/Task/SetterTaskTest.php rename to test.old/Task/SetterTaskTest.php index c49ed6b..3b2c51e 100644 --- a/Tests/Task/SetterTaskTest.php +++ b/test.old/Task/SetterTaskTest.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\CacheProcessBundle\Tests\Task; +namespace CleverAge\CacheProcessBundle\tests\Task; use CleverAge\ProcessBundle\Tests\AbstractProcessTest; diff --git a/Tests/Transformer/DeleterTransformerTest.php b/test.old/Transformer/DeleterTransformerTest.php similarity index 98% rename from Tests/Transformer/DeleterTransformerTest.php rename to test.old/Transformer/DeleterTransformerTest.php index 52f6ef7..e95b656 100644 --- a/Tests/Transformer/DeleterTransformerTest.php +++ b/test.old/Transformer/DeleterTransformerTest.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\CacheProcessBundle\Tests\Transformer; +namespace CleverAge\CacheProcessBundle\tests\Transformer; use CleverAge\ProcessBundle\Tests\AbstractProcessTest; use Psr\Cache\CacheItemPoolInterface; diff --git a/Tests/Transformer/GetterTransformerTest.php b/test.old/Transformer/GetterTransformerTest.php similarity index 98% rename from Tests/Transformer/GetterTransformerTest.php rename to test.old/Transformer/GetterTransformerTest.php index 4eb9c86..170caa9 100644 --- a/Tests/Transformer/GetterTransformerTest.php +++ b/test.old/Transformer/GetterTransformerTest.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\CacheProcessBundle\Tests\Transformer; +namespace CleverAge\CacheProcessBundle\tests\Transformer; use CleverAge\ProcessBundle\Tests\AbstractProcessTest; use Psr\Cache\CacheItemPoolInterface; diff --git a/Tests/Transformer/SetterTransformerTest.php b/test.old/Transformer/SetterTransformerTest.php similarity index 98% rename from Tests/Transformer/SetterTransformerTest.php rename to test.old/Transformer/SetterTransformerTest.php index e2f7b84..20d1b41 100644 --- a/Tests/Transformer/SetterTransformerTest.php +++ b/test.old/Transformer/SetterTransformerTest.php @@ -8,7 +8,7 @@ * file that was distributed with this source code. */ -namespace CleverAge\CacheProcessBundle\Tests\Transformer; +namespace CleverAge\CacheProcessBundle\tests\Transformer; use CleverAge\ProcessBundle\Tests\AbstractProcessTest; use Psr\Cache\CacheItemPoolInterface; diff --git a/Resources/tests/task/cache_deleter_task.yml b/test.old/task/cache_deleter_task.yml similarity index 100% rename from Resources/tests/task/cache_deleter_task.yml rename to test.old/task/cache_deleter_task.yml diff --git a/Resources/tests/task/cache_getter_task.yml b/test.old/task/cache_getter_task.yml similarity index 100% rename from Resources/tests/task/cache_getter_task.yml rename to test.old/task/cache_getter_task.yml diff --git a/Resources/tests/task/cache_setter_task.yml b/test.old/task/cache_setter_task.yml similarity index 100% rename from Resources/tests/task/cache_setter_task.yml rename to test.old/task/cache_setter_task.yml diff --git a/Resources/tests/transformer/cache_deleter_transformer.yml b/test.old/transformer/cache_deleter_transformer.yml similarity index 100% rename from Resources/tests/transformer/cache_deleter_transformer.yml rename to test.old/transformer/cache_deleter_transformer.yml diff --git a/Resources/tests/transformer/cache_getter_transformer.yml b/test.old/transformer/cache_getter_transformer.yml similarity index 100% rename from Resources/tests/transformer/cache_getter_transformer.yml rename to test.old/transformer/cache_getter_transformer.yml diff --git a/Resources/tests/transformer/cache_setter_transformer.yml b/test.old/transformer/cache_setter_transformer.yml similarity index 100% rename from Resources/tests/transformer/cache_setter_transformer.yml rename to test.old/transformer/cache_setter_transformer.yml diff --git a/tests/.gitkeep b/tests/.gitkeep new file mode 100644 index 0000000..e69de29