Skip to content

Commit

Permalink
Eager resettable services bundle
Browse files Browse the repository at this point in the history
  • Loading branch information
piotrkreft committed May 23, 2020
0 parents commit e764b8f
Show file tree
Hide file tree
Showing 21 changed files with 723 additions and 0 deletions.
35 changes: 35 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: CI

on:
push:
branches: [ master ]

jobs:
ci:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2

- name: Install PHP
uses: shivammathur/setup-php@v2
with:
php-version: 7.4
coverage: pcov

- name: Install dependencies
run: composer update --prefer-dist --no-progress --no-suggest --prefer-stable

- name: PHPUnit with coverage
run: vendor/bin/phpunit --coverage-clover=build/logs/clover.xml tests

- name: Report coverage
run: vendor/bin/php-coveralls
env:
COVERALLS_RUN_LOCALLY: yes
COVERALLS_REPO_TOKEN: ${{ secrets.COVERALLS_REPO_TOKEN }}

- name: Infection mutations
run: vendor/bin/infection --show-mutations
env:
INFECTION_BADGE_API_KEY: ${{ secrets.INFECTION_BADGE_API_KEY }}
32 changes: 32 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: Tests

on:
push:
branches: [ master ]
pull_request:
branches: [ master ]

jobs:
tests:
runs-on: ubuntu-latest
strategy:
matrix:
php-versions: ['7.3','7.4']
composer-opts: ['--prefer-lowest', '']

steps:
- uses: actions/checkout@v2

- name: Install PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php-versions }}

- name: Validate dependencies
run: composer validate

- name: Install dependencies
run: composer update --prefer-dist --no-progress --no-suggest ${{ matrix.composer-opts }} --prefer-stable

- name: Run test suite
run: composer test
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/var/
/vendor/
.idea
composer.lock
infection.log
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Eager resettable services bundle

![CI](https://github.com/piotrkreft/eager-resettable-services-bundle/workflows/CI/badge.svg)
[![Coverage Status](https://coveralls.io/repos/github/piotrkreft/eager-resettable-services-bundle/badge.svg)](https://coveralls.io/github/piotrkreft/eager-resettable-services-bundle)
[![Mutation testing badge](https://img.shields.io/endpoint?style=flat&url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fpiotrkreft%2Feager-resettable-services-bundle%2Fmaster)](https://infection.github.io)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/piotrkreft/eager-resettable-services-bundle/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/piotrkreft/eager-resettable-services-bundle/?branch=master)

Symfony bundle for eager instantiating resettable services.

## Introduction
For some edge cases it might be required that service gets reset regardless of being referenced by other services.

An example of that would be `doctrine` Registry holding Entity Managers.
It does not reset managers unless it is being referenced by other services and therefore instantiated by the container.

This bundle by the configuration allows you to reconfigure services to be eagerly instantiated within Services Resetter.

## Example
[example configuration](tests/Fixtures/Resources/config/config.yaml)

Alternatively all services can be eager loaded wth `all_services` configuration flag.
47 changes: 47 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"name": "piotrkreft/eager-resettable-services-bundle",
"type": "symfony-bundle",
"description": "Flexible management of Symfony resettable services",
"license": "MIT",
"authors": [
{
"name": "Piotr Kreft",
"email": "[email protected]"
}
],
"require": {
"php": "^7.3",
"symfony/config": "^4.2|^5.0",
"symfony/dependency-injection": "^4.0|^5.0",
"symfony/http-kernel": "^4.0|^5.0"
},
"require-dev": {
"piotrkreft/ci": "^0.1",
"symfony/framework-bundle": "^4.0|^5.0",
"symfony/yaml": "^4.0|^5.0"
},
"autoload": {
"psr-4": {
"PK\\EagerResettableServicesBundle\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"PK\\Tests\\EagerResettableServicesBundle\\": "tests/"
}
},
"minimum-stability": "dev",
"scripts": {
"test": [
"@prepare-cache",
"vendor/bin/pk-tests --cache-dir=./var/cache run"
],
"fix": [
"@prepare-cache",
"vendor/bin/pk-tests --cache-dir=./var/cache fix"
],
"prepare-cache": [
"mkdir -p var/cache"
]
}
}
13 changes: 13 additions & 0 deletions infection.json.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"source": {
"directories": [
"src"
]
},
"logs": {
"text": "var/cache/infection.log",
"badge": {
"branch": "master"
}
}
}
20 changes: 20 additions & 0 deletions phpunit.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit
beStrictAboutCoversAnnotation="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
verbose="true"
>

<testsuites>
<testsuite name="default">
<directory suffix="Test.php">tests</directory>
</testsuite>
</testsuites>

<filter>
<whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">src</directory>
</whitelist>
</filter>
</phpunit>
37 changes: 37 additions & 0 deletions src/DependencyInjection/Compiler/EagerResettableServicesPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace PK\EagerResettableServicesBundle\DependencyInjection\Compiler;

use Symfony\Component\DependencyInjection\Argument\ArgumentInterface;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

class EagerResettableServicesPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
$allServices = $container->getParameter('pk_eager_resettable_services.all_services');
$services = $container->getParameter('pk_eager_resettable_services.services');

if (!$container->has('services_resetter') || !$services && !$allServices) {
return;
}

/** @var ArgumentInterface $resettableServices */
$resettableServices = $container->getDefinition('services_resetter')->getArgument(0);
$overrideResettableServices = [];

foreach ($resettableServices->getValues() as $serviceId => $reference) {
if (($allServices || in_array($serviceId, $services)) && $container->hasDefinition($serviceId)) {
$overrideResettableServices[$serviceId] = new Reference($serviceId);
continue;
}
$overrideResettableServices[$serviceId] = $reference;
}

$resettableServices->setValues($overrideResettableServices);
}
}
31 changes: 31 additions & 0 deletions src/DependencyInjection/Compiler/ValidateServicesPass.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

declare(strict_types=1);

namespace PK\EagerResettableServicesBundle\DependencyInjection\Compiler;

use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;

class ValidateServicesPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container): void
{
$notExisting = [];
foreach ($container->getParameter('pk_eager_resettable_services.services') as $serviceId) {
if ($container->hasDefinition($serviceId) || $container->hasAlias($serviceId)) {
continue;
}
$notExisting[] = $serviceId;
}
if (!$notExisting) {
return;
}

throw new InvalidConfigurationException(sprintf(
'Missing resettable services for eager initialization (%s).',
implode(', ', $notExisting)
));
}
}
28 changes: 28 additions & 0 deletions src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?php

declare(strict_types=1);

namespace PK\EagerResettableServicesBundle\DependencyInjection;

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

class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder(): TreeBuilder
{
$treeBuilder = new TreeBuilder('pk_eager_resettable_services');

$treeBuilder
->getRootNode()
->children()
->arrayNode('services')
->scalarPrototype()->end()
->end()
->booleanNode('all_services')->defaultFalse()->end()
->end()
->end();

return $treeBuilder;
}
}
23 changes: 23 additions & 0 deletions src/DependencyInjection/PKEagerResettableServicesExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace PK\EagerResettableServicesBundle\DependencyInjection;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension;

class PKEagerResettableServicesExtension extends Extension
{
/**
* {@inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container): void
{
$configuration = $this->getConfiguration($configs, $container);
$config = $this->processConfiguration($configuration, $configs);

$container->setParameter('pk_eager_resettable_services.services', $config['services']);
$container->setParameter('pk_eager_resettable_services.all_services', $config['all_services']);
}
}
22 changes: 22 additions & 0 deletions src/PKEagerResettableServicesBundle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

declare(strict_types=1);

namespace PK\EagerResettableServicesBundle;

use PK\EagerResettableServicesBundle\DependencyInjection\Compiler\EagerResettableServicesPass;
use PK\EagerResettableServicesBundle\DependencyInjection\Compiler\ValidateServicesPass;
use Symfony\Component\DependencyInjection\Compiler\PassConfig;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Bundle\Bundle;

class PKEagerResettableServicesBundle extends Bundle
{
public function build(ContainerBuilder $container): void
{
$container
->addCompilerPass(new ValidateServicesPass())
->addCompilerPass(new EagerResettableServicesPass(), PassConfig::TYPE_REMOVE)
;
}
}
Loading

0 comments on commit e764b8f

Please sign in to comment.