8000 feature #27093 Add symfony/contracts: a set of abstractions extracted… · fancyweb/symfony@1e16a8b · GitHub
[go: up one dir, main page]

Skip to content

Commit 1e16a8b

Browse files
committed
feature symfony#27093 Add symfony/contracts: a set of abstractions extracted out of the Symfony components (nicolas-grekas)
This PR was merged into the 4.2-dev branch. Discussion ---------- Add symfony/contracts: a set of abstractions extracted out of the Symfony components | Q | A | ------------- | --- | Branch? | master | Bug fix? | no | New feature? | yes | BC breaks? | - | Deprecations? | no | Tests pass? | yes | Fixed tickets | - | License | MIT | Doc PR | - A set of abstractions extracted out of the Symfony components. This is a topic I've been thinking about for a long time. I feel like the time has come for Symfony to publish some abstractions so that people could build on them in a decoupled way. I've identified interfaces in some components that would greatly benefit from being moved out from the components where they are for now. E.g. symfony#26929 is something that has a broader scope than the Cache component itself. By putting them in a new `symfony/abstractions` package, we would allow more innovation in the Symfony community, at the abstraction level. In order to start small, I propose only one interface that gathers a concept that is shared amongst many components already: `ResetInterface`. It would provide a standard `reset()` method, whose purpose is to set an object back to its initial state, allowing it to be reused many times with no side effects/leaks related to its history. By this definition, it could also be autoconfigured (as done here, see update in FrameworkExtension). See wording in the docblock in the attached source code. Ideally, I'd like this package to provide not only interfaces, by also generic traits, and reference test suites when possible. We could work on adding more abstractions during the 4.2 cycle. WDYT? ## Here is the attached README: A set of abstractions extracted out of the Symfony components. Can be used to build on semantics that the Symfony components proved useful - and that already have battle tested implementations. Design Principles ----------------- * contracts are split by domain, each into their own sub-namespaces; * contracts are small and consistent sets of PHP interfaces, traits, normative docblocks and reference test suites when applicable, etc.; * all contracts must have a proven implementation to enter this repository; * they must be backward compatible with existing Symfony components. FAQ --- ### How to use this package? The abstractions in this package are useful to achieve loose coupling and interoperability. By using the provided interfaces as type hints, you are able to reuse any implementations that match their contracts. It could be a Symfony component, or another one provided by the PHP community at large. Depending on their semantics, some interfaces can be combined with autowiring to seamlessly inject a service in your classes. Others might be useful as labeling interfaces, to hint about a specific behavior that could be enabled when using autoconfiguration or manual service tagging (or any other means provided by your framework.) ### How is this different from PHP-FIG's PSRs? When applicable, the provided contracts are built on top of PHP-FIG's PSR. We encourage relying on them and won't duplicate the effort. Still, the FIG has different goals and different processes. Here, we don't need to seek universal standards. Instead, we're providing abstractions that are compatible with the implementations provided by Symfony. This should actually also contribute positively to the PHP-FIG (from which Symfony is a member), by hinting the group at some abstractions the PHP world might like to take inspiration from. ### Why isn't this package split into several packages? Putting all interfaces in one package eases discoverability and dependency management. Instead of dealing with a myriad of small packages and the corresponding matrix of versions, you just need to deal with one package and one version. Also when using IDE autocompletion or just reading the source code, it makes it easier to figure out which contracts are provided. There are two downsides to this approach: you may have unused files in your `vendor/` directory, and in the future, it will be impossible to use two different sub-namespaces in different major versions of the package. For the "unused files" downside, it has no practical consequences: their file sizes are very small, and there is no performance overhead at all since they are never loaded. For major versions, this package follows the Symfony BC + deprecation policies, with an additional restriction to never remove deprecated interfaces. Resources --------- * [Documentation](https://symfony.com/doc/current/components/contracts.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) Commits ------- 8982036 Added symfony/contracts: a set of abstractions extracted out of the components
2 parents 5e28ac3 + 8982036 commit 1e16a8b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+288
-45
lines changed

.github/build-packages.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949

5050
$packages[$package->name][$package->version] = $package;
5151

52-
$versions = file_get_contents('https://packagist.org/p/'.$package->name.'.json');
52+
$versions = @file_get_contents('https://packagist.org/p/'.$package->name.'.json') ?: sprintf('{"packages":{"%s":{"dev-master":%s}}}', $package->name, file_get_contents($dir.'/composer.json'));
5353
$versions = json_decode($versions)->packages->{$package->name};
5454

5555
if ($package->version === str_replace('-dev', '.x-dev', $versions->{'dev-master'}->extra->{'branch-alias'}->{'dev-master'})) {

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ before_install:
124124
deps=skip
125125
skip=1
126126
else
127-
COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n')
127+
COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h\n')
128128
fi
129129
130130
- |
@@ -181,7 +181,7 @@ install:
181181
SYMFONY_VERSION=$(git ls-remote --heads | grep -o '/[1-9].*' | tail -n 1 | sed s/.//) &&
182182
git fetch origin $SYMFONY_VERSION &&
183183
git checkout -m FETCH_HEAD &&
184-
COMPONENTS=$(find src/Symfony -mindepth 3 -type f -name phpunit.xml.dist -printf '%h\n')
184+
COMPONENTS=$(find src/Symfony -mindepth 2 -type f -name phpunit.xml.dist -printf '%h\n')
185185
elif [[ ! $skip ]]; then
186186
SYMFONY_VERSION=$(cat composer.json | grep '^ *"dev-master". *"[1-9]' | grep -o '[0-9.]*')
187187
fi

composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
"symfony/cache": "self.version",
3838
"symfony/config": "self.version",
3939
"symfony/console": "self.version",
40+
"symfony/contracts": "1.0.0",
4041
"symfony/css-selector": "self.version",
4142
"symfony/dependency-injection": "self.version",
4243
"symfony/debug": "self.version",
@@ -118,7 +119,8 @@
118119
"Symfony\\Bridge\\ProxyManager\\": "src/Symfony/Bridge/ProxyManager/",
119120
"Symfony\\Bridge\\Twig\\": "src/Symfony/Bridge/Twig/",
120121
"Symfony\\Bundle\\": "src/Symfony/Bundle/",
121-
"Symfony\\Component\\": "src/Symfony/Component/"
122+
"Symfony\\Component\\": "src/Symfony/Component/",
123+
"Symfony\\Contract\\": "src/Symfony/Contract/"
122124
},
123125
"classmap": [
124126
"src/Symfony/Component/Intl/Resources/stubs"

phpunit.xml.dist

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
<directory>./src/Symfony/Bridge/*/Tests/</directory>
2727
<directory>./src/Symfony/Component/*/Tests/</directory>
2828
<directory>./src/Symfony/Component/*/*/Tests/</directory>
29+
<directory>./src/Symfony/Contract/*/Tests/</directory>
2930
<directory>./src/Symfony/Bundle/*/Tests/</directory>
3031
</testsuite>
3132
</testsuites>
@@ -44,6 +45,7 @@
4445
<directory>./src/Symfony/Bridge/*/Tests</directory>
4546
<directory>./src/Symfony/Component/*/Tests</directory>
4647
<directory>./src/Symfony/Component/*/*/Tests</directory>
48+
<directory>./src/Symfony/Contract/*/Tests</directory>
4749
<directory>./src/Symfony/Bundle/*/Tests</directory>
4850
<directory>./src/Symfony/Bundle/*/Resources</directory>
4951
<directory>./src/Symfony/Component/*/Resources</directory>
@@ -52,6 +54,7 @@
5254
<directory>./src/Symfony/Bundle/*/vendor</directory>
5355
<directory>./src/Symfony/Component/*/vendor</directory>
5456
<directory>./src/Symfony/Component/*/*/vendor</directory>
57+
<directory>./src/Symfony/Contract/*/vendor</directory>
5558
</exclude>
5659
</whitelist>
5760
</filter>

src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@
2424
use Symfony\Component\Form\FormBuilderInterface;
2525
use Symfony\Component\OptionsResolver\Options;
2626
use Symfony\Component\OptionsResolver\OptionsResolver;
27+
use Symfony\Contract\Service\ResetInterface;
2728

28-
abstract class DoctrineType extends AbstractType
29+
abstract class DoctrineType extends AbstractType implements ResetInterface
2930
{
3031
/**
3132
* @var ManagerRegistry

src/Symfony/Bridge/Doctrine/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"require": {
1919
"php": "^7.1.3",
2020
"doctrine/common": "~2.4@stable",
21+
"symfony/contracts": "^1.0",
2122
"symfony/polyfill-ctype": "~1.8",
2223
"symfony/polyfill-mbstring": "~1.0"
2324
},

src/Symfony/Bridge/Monolog/Logger.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@
1414
use Monolog\Logger as BaseLogger;
1515
use Symfony\Component\HttpFoundation\Request;
1616
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
17+
use Symfony\Contract\Service\ResetInterface;
1718

1819
/**
1920
* Logger.
2021
*
2122
* @author Fabien Potencier <fabien@symfony.com>
2223
*/
23-
class Logger extends BaseLogger implements DebugLoggerInterface
24+
class Logger extends BaseLogger implements DebugLoggerInterface, ResetInterface
2425
{
2526
/**
2627
* {@inheritdoc}
@@ -56,6 +57,14 @@ public function clear()
5657
}
5758
}
5859

60+
/**
61+
* {@inheritdoc}
62+
*/
63+
public function reset()
64+
{
65+
$this->clear();
66+
}
67+
5968
/**
6069
* Returns a DebugLoggerInterface instance if one is registered with this logger.
6170
*

src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515
use Symfony\Component\HttpFoundation\Request;
1616
use Symfony\Component\HttpFoundation\RequestStack;
1717
use Symfony\Component\HttpKernel\Log\DebugLoggerInterface;
18+
use Symfony\Contract\Service\ResetInterface;
1819

19-
class DebugProcessor implements DebugLoggerInterface
20+
class DebugProcessor implements DebugLoggerInterface, ResetInterface
2021
{
2122
private $records = array();
2223
private $errorCount = array();
@@ -91,4 +92,12 @@ public function clear()
9192
$this->records = array();
9293
$this->errorCount = array();
9394
}
95+
96+
/**
97+
* {@inheritdoc}
98+
*/
99+
public function reset()
100+
{
101+
$this->clear();
102+
}
94103
}

src/Symfony/Bridge/Monolog/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
"require": {
1919
"php": "^7.1.3",
2020
"monolog/monolog": "~1.19",
21+
"symfony/contracts": "^1.0",
2122
"symfony/http-kernel": "~3.4|~4.0"
2223
},
2324
"require-dev": {

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
use Symfony\Component\Cache\Adapter\ArrayAdapter;
2626
use Symfony\Component\Cache\Adapter\TagAwareAdapter;
2727
use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
28-
use Symfony\Component\Cache\ResettableInterface;
2928
use Symfony\Component\Config\FileLocator;
3029
use Symfony\Component\Config\Loader\LoaderInterface;
3130
use Symfony\Component\Config\Resource\DirectoryResource;
@@ -95,6 +94,7 @@
9594
use Symfony\Component\Workflow;
9695
use Symfony\Component\Yaml\Command\LintCommand as BaseYamlLintCommand;
9796
use Symfony\Component\Yaml\Yaml;
97+
use Symfony\Contract\Service\ResetInterface;
9898

9999
/**
100100
* FrameworkExtension.
@@ -324,7 +324,7 @@ public function load(array $configs, ContainerBuilder $container)
324324
->addTag('kernel.cache_warmer');
325325
$container->registerForAutoconfiguration(EventSubscriberInterface::class)
326326
->addTag('kernel.event_subscriber');
327-
$container->registerForAutoconfiguration(ResettableInterface::class)
327+
$container->registerForAutoconfiguration(ResetInterface::class)
328328
->addTag('kernel.reset', array('method' => 'reset'));
329329
$container->registerForAutoconfiguration(ProcessorInterface::class)
330330
->addTag('monolog.processor');

src/Symfony/Component/Cache/Adapter/ChainAdapter.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
use Symfony\Component\Cache\PruneableInterface;
2020
use Symfony\Component\Cache\ResettableInterface;
2121
use Symfony\Component\Cache\Traits\GetTrait;
22+
use Symfony\Contract\Service\ResetInterface;
2223

2324
/**
2425
* Chains several adapters together.
@@ -301,7 +302,7 @@ public function prune()
301302
public function reset()
302303
{
303304
foreach ($this->adapters as $adapter) {
304-
if ($adapter instanceof ResettableInterface) {
305+
if ($adapter instanceof ResetInterface) {
305306
$adapter->reset();
306307
}
307308
}

src/Symfony/Component/Cache/Adapter/TraceableAdapter.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
use Symfony\Component\Cache\CacheItem;
1717
use Symfony\Component\Cache\PruneableInterface;
1818
use Symfony\Component\Cache\ResettableInterface;
19+
use Symfony\Contract\Service\ResetInterface;
1920

2021
/**
2122
* An adapter that collects data about all cache calls.
@@ -225,7 +226,7 @@ public function prune()
225226
*/
226227
public function reset()
227228
{
228-
if (!$this->pool instanceof ResettableInterface) {
229+
if (!$this->pool instanceof ResetInterface) {
229230
return;
230231
}
231232
$event = $this->start(__FUNCTION__);

src/Symfony/Component/Cache/DoctrineProvider.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
use Doctrine\Common\Cache\CacheProvider;
1515
use Psr\Cache\CacheItemPoolInterface;
16+
use Symfony\Contract\Service\ResetInterface;
1617

1718
/**
1819
* @author Nicolas Grekas <p@tchwork.com>
@@ -39,7 +40,7 @@ public function prune()
3940
*/
4041
public function reset()
4142
{
42-
if ($this->pool instanceof ResettableInterface) {
43+
if ($this->pool instanceof ResetInterface) {
4344
$this->pool->reset();
4445
}
4546
$this->setNamespace($this->getNamespace());

src/Symfony/Component/Cache/ResettableInterface.php

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,11 @@
1111

1212
namespace Symfony\Component\Cache;
1313

14+
use Symfony\Contract\Service\ResetInterface;
15+
1416
/**
1517
* Resets a pool's local state.
1618
*/
17-
interface ResettableInterface
19+
interface ResettableInterface extends ResetInterface
1820
{
19-
public function reset();
2021
}

src/Symfony/Component/Cache/Simple/ChainCache.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
use Symfony\Component\Cache\Exception\InvalidArgumentException;
1616
use Symfony\Component\Cache\PruneableInterface;
1717
use Symfony\Component\Cache\ResettableInterface;
18+
use Symfony\Contract\Service\ResetInterface;
1819

1920
/**
2021
* Chains several caches together.
@@ -244,7 +245,7 @@ public function prune()
244245
public function reset()
245246
{
246247
foreach ($this->caches as $cache) {
247-
if ($cache instanceof ResettableInterface) {
248+
if ($cache instanceof ResetInterface) {
248249
$cache->reset();
249250
}
250251
}

src/Symfony/Component/Cache/Simple/TraceableCache.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Psr\SimpleCache\CacheInterface;
1515
use Symfony\Component\Cache\PruneableInterface;
1616
use Symfony\Component\Cache\ResettableInterface;
17+
use Symfony\Contract\Service\ResetInterface;
1718

1819
/**
1920
* An adapter that collects data about all cache calls.
@@ -200,7 +201,7 @@ public function prune()
200201
*/
201202
public function reset()
202203
{
203-
if (!$this->pool instanceof ResettableInterface) {
204+
if (!$this->pool instanceof ResetInterface) {
204205
return;
205206
}
206207
$event = $this->start(__FUNCTION__);

src/Symfony/Component/Cache/Traits/ProxyTrait.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
namespace Symfony\Component\Cache\Traits;
1313

1414
use Symfony\Component\Cache\PruneableInterface;
15-
use Symfony\Component\Cache\ResettableInterface;
15+
use Symfony\Contract\Service\ResetInterface;
1616

1717
/**
1818
* @author Nicolas Grekas <p@tchwork.com>
@@ -36,7 +36,7 @@ public function prune()
3636
*/
3737
public function reset()
3838
{
39-
if ($this->pool instanceof ResettableInterface) {
39+
if ($this->pool instanceof ResetInterface) {
4040
$this->pool->reset();
4141
}
4242
}

src/Symfony/Component/Cache/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@
2323
"php": "^7.1.3",
2424
"psr/cache": "~1.0",
2525
"psr/log": "~1.0",
26-
"psr/simple-cache": "^1.0"
26+
"psr/simple-cache": "^1.0",
27+
"symfony/contracts": "^1.0"
2728
},
2829
"require-dev": {
2930
"cache/integration-tests": "dev-master",

src/Symfony/Component/Console/Formatter/OutputFormatterStyleStack.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,12 @@
1212
namespace Symfony\Component\Console\Formatter;
1313

1414
use Symfony\Component\Console\Exception\InvalidArgumentException;
15+
use Symfony\Contract\Service\ResetInterface;
1516

1617
/**
1718
* @author Jean-François Simon <contact@jfsimon.fr>
1819
*/
19-
class OutputFormatterStyleStack
20+
class OutputFormatterStyleStack implements ResetInterface
2021
{
2122
/**
2223
* @var OutputFormatterStyleInterface[]

src/Symfony/Component/Console/composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
],
1818
"require": {
1919
"php": "^7.1.3",
20+
"symfony/contracts": "^1.0",
2021
"symfony/polyfill-mbstring": "~1.0"
2122
},
2223
"require-dev": {

src/Symfony/Component/DependencyInjection/ResettableContainerInterface.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,16 @@
1111

1212
namespace Symfony\Component\DependencyInjection;
1313

14+
use Symfony\Contract\Service\ResetInterface;
15+
1416
/**
1517
* ResettableContainerInterface defines additional resetting functionality
1618
* for containers, allowing to release shared services when the container is
1719
* not needed anymore.
1820
*
1921
* @author Christophe Coevoet <stof@notk.org>
2022
*/
21-
interface ResettableContainerInterface extends ContainerInterface
23+
interface ResettableContainerInterface extends ContainerInterface, ResetInterface
2224
{
2325
/**
2426
* Resets shared services from the container.

src/Symfony/Component/DependencyInjection/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
],
1818
"require": {
1919
"php": "^7.1.3",
20-
"psr/container": "^1.0"
10000 20+
"psr/container": "^1.0",
21+
"symfony/contracts": "^1.0"
2122
},
2223
"require-dev": {
2324
"symfony/yaml": "~3.4|~4.0",

src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcherInterface.php

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@
1212
namespace Symfony\Component\EventDispatcher\Debug;
1313

1414
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
15+
use Symfony\Contract\Service\ResetInterface;
1516

1617
/**
1718
* @deprecated since Symfony 4.1
1819
*
1920
* @author Fabien Potencier <fabien@symfony.com>
2021
*/
21-
interface TraceableEventDispatcherInterface extends EventDispatcherInterface
22+
interface TraceableEventDispatcherInterface extends EventDispatcherInterface, ResetInterface
2223
{
2324
/**
2425
* Gets the called listeners.
@@ -33,9 +34,4 @@ public function getCalledListeners();
3334
* @return array An array of not called listeners
3435
*/
3536
public function getNotCalledListeners();
36-
37-
/**
38-
* Resets the trace.
39-
*/
40-
public function reset();
4137
}

src/Symfony/Component/EventDispatcher/composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
}
1717
],
1818
"require": {
19-
"php": "^7.1.3"
19+
"php": "^7.1.3",
20+
"symfony/contracts": "^1.0"
2021
},
2122
"require-dev": {
2223
"symfony/dependency-injection": "~3.4|~4.0",

0 commit comments

Comments
 (0)
0