Skip to content

Commit

Permalink
Merge branch '4.3'
Browse files Browse the repository at this point in the history
* 4.3: (23 commits)
  minor: add some test in the ldap component
  [Workflow] Update MethodMarkingStore
  [Bridge\ProxyManager] isProxyCandidate() does not take into account interfaces
  adding experimental note
  [HttpClient] add missing argument check
  [Messenger] Fix undefined index on read timeout
  [Workflow] use method marking store
  [Routing][AnnotationClassLoader] fix utf-8 encoding in default route name
  fixed a phpdoc
  [Debug] Wrap call to require_once in a try/catch
  [EventDispatcher] Removed "callable" type hint from WrappedListener constructor
  prevent deprecation when filesize matches error code
  [PropertyInfo] Add missing documentation link in Readme
  Use the current working dir as default first arg in 'link' binary
  Respect parent class contract in ContainerAwareDoctrineEventManager
  [WebProfilerBundle][Form] The form data collector return serialized object when profiler bundle attends object
  [Validator] Add the missing translations for the Danish ("da") locale
  [PropertyAccess] Add missing property to PropertyAccessor
  [Cache] fix saving unrelated keys in recursive callback calls
  [Serializer] Fix denormalization of object with variadic constructor typed argument
  ...
  • Loading branch information
nicolas-grekas committed May 20, 2019
2 parents 5bf7759 + 2ecad3f commit beb6036
Show file tree
Hide file tree
Showing 34 changed files with 479 additions and 89 deletions.
16 changes: 7 additions & 9 deletions link
Expand Up @@ -23,14 +23,12 @@ use Symfony\Component\Filesystem\Filesystem;
* @author Kévin Dunglas <dunglas@gmail.com>
*/

if (2 !== $argc) {
echo 'Link dependencies to components to a local clone of the main symfony/symfony GitHub repository.'.PHP_EOL.PHP_EOL;
echo "Usage: $argv[0] /path/to/the/project".PHP_EOL;
exit(1);
}
$pathToProject = $argv[1] ?? getcwd();

if (!is_dir("$argv[1]/vendor/symfony")) {
echo "The directory \"$argv[1]\" does not exist or the dependencies are not installed, did you forget to run \"composer install\" in your project?".PHP_EOL;
if (!is_dir("$pathToProject/vendor/symfony")) {
echo 'Link dependencies to components to a local clone of the main symfony/symfony GitHub repository.'.PHP_EOL.PHP_EOL;
echo "Usage: $argv[0] /path/to/the/project".PHP_EOL.PHP_EOL;
echo "The directory \"$pathToProject\" does not exist or the dependencies are not installed, did you forget to run \"composer install\" in your project?".PHP_EOL;
exit(1);
}

Expand All @@ -50,7 +48,7 @@ foreach ($directories as $dir) {
}
}

foreach (glob("$argv[1]/vendor/symfony/*", GLOB_ONLYDIR | GLOB_NOSORT) as $dir) {
foreach (glob("$pathToProject/vendor/symfony/*", GLOB_ONLYDIR | GLOB_NOSORT) as $dir) {
$package = 'symfony/'.basename($dir);
if (is_link($dir)) {
echo "\"$package\" is already a symlink, skipping.".PHP_EOL;
Expand All @@ -68,6 +66,6 @@ foreach (glob("$argv[1]/vendor/symfony/*", GLOB_ONLYDIR | GLOB_NOSORT) as $dir)
echo "\"$package\" has been linked to \"$sfPackages[$package]\".".PHP_EOL;
}

foreach (glob("$argv[1]/var/cache/*") as $cacheDir) {
foreach (glob("$pathToProject/var/cache/*") as $cacheDir) {
$filesystem->remove($cacheDir);
}
89 changes: 46 additions & 43 deletions src/Symfony/Bridge/Doctrine/ContainerAwareEventManager.php
Expand Up @@ -37,72 +37,61 @@ public function __construct(ContainerInterface $container)
}

/**
* Dispatches an event to all registered listeners.
*
* @param string $eventName The name of the event to dispatch. The name of the event is
* the name of the method that is invoked on listeners.
* @param EventArgs $eventArgs The event arguments to pass to the event handlers/listeners.
* If not supplied, the single empty EventArgs instance is used.
*
* @return bool
* {@inheritdoc}
*/
public function dispatchEvent($eventName, EventArgs $eventArgs = null)
{
if (isset($this->listeners[$eventName])) {
$eventArgs = null === $eventArgs ? EventArgs::getEmptyInstance() : $eventArgs;
if (!isset($this->listeners[$eventName])) {
return;
}

$initialized = isset($this->initialized[$eventName]);
$eventArgs = null === $eventArgs ? EventArgs::getEmptyInstance() : $eventArgs;

foreach ($this->listeners[$eventName] as $hash => $listener) {
if (!$initialized && \is_string($listener)) {
$this->listeners[$eventName][$hash] = $listener = $this->container->get($listener);
}
if (!isset($this->initialized[$eventName])) {
$this->initializeListeners($eventName);
}

$listener->$eventName($eventArgs);
}
$this->initialized[$eventName] = true;
foreach ($this->listeners[$eventName] as $hash => $listener) {
$listener->$eventName($eventArgs);
}
}

/**
* Gets the listeners of a specific event or all listeners.
*
* @param string $event The name of the event
*
* @return array The event listeners for the specified event, or all event listeners
* {@inheritdoc}
*/
public function getListeners($event = null)
{
return $event ? $this->listeners[$event] : $this->listeners;
if (null !== $event) {
if (!isset($this->initialized[$event])) {
$this->initializeListeners($event);
}

return $this->listeners[$event];
}

foreach ($this->listeners as $event => $listeners) {
if (!isset($this->initialized[$event])) {
$this->initializeListeners($event);
}
}

return $this->listeners;
}

/**
* Checks whether an event has any registered listeners.
*
* @param string $event
*
* @return bool TRUE if the specified event has any listeners, FALSE otherwise
* {@inheritdoc}
*/
public function hasListeners($event)
{
return isset($this->listeners[$event]) && $this->listeners[$event];
}

/**
* Adds an event listener that listens on the specified events.
*
* @param string|array $events The event(s) to listen on
* @param object|string $listener The listener object
*
* @throws \RuntimeException
* {@inheritdoc}
*/
public function addEventListener($events, $listener)
{
if (\is_string($listener)) {
if ($this->initialized) {
throw new \RuntimeException('Adding lazy-loading listeners after construction is not supported.');
}

$hash = '_service_'.$listener;
} else {
// Picks the hash code related to that listener
Expand All @@ -113,14 +102,15 @@ public function addEventListener($events, $listener)
// Overrides listener if a previous one was associated already
// Prevents duplicate listeners on same event (same instance only)
$this->listeners[$event][$hash] = $listener;

if (\is_string($listener)) {
unset($this->initialized[$event]);
}
}
}

/**
* Removes an event listener from the specified events.
*
* @param string|array $events
* @param object|string $listener
* {@inheritdoc}
*/
public function removeEventListener($events, $listener)
{
Expand All @@ -138,4 +128,17 @@ public function removeEventListener($events, $listener)
}
}
}

/**
* @param string $eventName
*/
private function initializeListeners($eventName)
{
foreach ($this->listeners[$eventName] as $hash => $listener) {
if (\is_string($listener)) {
$this->listeners[$eventName][$hash] = $this->container->get($listener);
}
}
$this->initialized[$eventName] = true;
}
}
Expand Up @@ -28,8 +28,8 @@ protected function setUp()

public function testDispatchEvent()
{
$this->container->set('foobar', $listener1 = new MyListener());
$this->evm->addEventListener('foo', 'foobar');
$this->container->set('lazy', $listener1 = new MyListener());
$this->evm->addEventListener('foo', 'lazy');
$this->evm->addEventListener('foo', $listener2 = new MyListener());

$this->evm->dispatchEvent('foo');
Expand All @@ -38,19 +38,69 @@ public function testDispatchEvent()
$this->assertTrue($listener2->called);
}

public function testAddEventListenerAfterDispatchEvent()
{
$this->container->set('lazy1', $listener1 = new MyListener());
$this->evm->addEventListener('foo', 'lazy1');
$this->evm->addEventListener('foo', $listener2 = new MyListener());

$this->evm->dispatchEvent('foo');

$this->container->set('lazy2', $listener3 = new MyListener());
$this->evm->addEventListener('foo', 'lazy2');
$this->evm->addEventListener('foo', $listener4 = new MyListener());

$this->evm->dispatchEvent('foo');

$this->assertTrue($listener1->called);
$this->assertTrue($listener2->called);
$this->assertTrue($listener3->called);
$this->assertTrue($listener4->called);
}

public function testGetListenersForEvent()
{
$this->container->set('lazy', $listener1 = new MyListener());
$this->evm->addEventListener('foo', 'lazy');
$this->evm->addEventListener('foo', $listener2 = new MyListener());

$this->assertSame([$listener1, $listener2], array_values($this->evm->getListeners('foo')));
}

public function testGetListeners()
{
$this->container->set('lazy', $listener1 = new MyListener());
$this->evm->addEventListener('foo', 'lazy');
$this->evm->addEventListener('foo', $listener2 = new MyListener());

$this->assertSame([$listener1, $listener2], array_values($this->evm->getListeners()['foo']));
}

public function testRemoveEventListener()
{
$this->evm->addEventListener('foo', 'bar');
$this->evm->addEventListener('foo', $listener = new MyListener());
$this->container->set('lazy', $listener1 = new MyListener());
$this->evm->addEventListener('foo', 'lazy');
$this->evm->addEventListener('foo', $listener2 = new MyListener());

$this->evm->removeEventListener('foo', $listener2);
$this->assertSame([$listener1], array_values($this->evm->getListeners('foo')));

$listeners = ['foo' => ['_service_bar' => 'bar', spl_object_hash($listener) => $listener]];
$this->assertSame($listeners, $this->evm->getListeners());
$this->assertSame($listeners['foo'], $this->evm->getListeners('foo'));
$this->evm->removeEventListener('foo', 'lazy');
$this->assertSame([], $this->evm->getListeners('foo'));
}

public function testRemoveEventListenerAfterDispatchEvent()
{
$this->container->set('lazy', $listener1 = new MyListener());
$this->evm->addEventListener('foo', 'lazy');
$this->evm->addEventListener('foo', $listener2 = new MyListener());

$this->evm->dispatchEvent('foo');

$this->evm->removeEventListener('foo', $listener);
$this->assertSame(['_service_bar' => 'bar'], $this->evm->getListeners('foo'));
$this->evm->removeEventListener('foo', $listener2);
$this->assertSame([$listener1], array_values($this->evm->getListeners('foo')));

$this->evm->removeEventListener('foo', 'bar');
$this->evm->removeEventListener('foo', 'lazy');
$this->assertSame([], $this->evm->getListeners('foo'));
}
}
Expand Down
Expand Up @@ -14,6 +14,7 @@
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface;

/**
* Tests for {@see \Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper}.
Expand Down Expand Up @@ -182,6 +183,7 @@ public function getProxyCandidates()
$definitions = [
[new Definition(__CLASS__), true],
[new Definition('stdClass'), true],
[new Definition(DumperInterface::class), true],
[new Definition(uniqid('foo', true)), false],
[new Definition(), false],
];
Expand Down
3 changes: 2 additions & 1 deletion src/Symfony/Bundle/WebProfilerBundle/composer.json
Expand Up @@ -32,7 +32,8 @@
"conflict": {
"symfony/dependency-injection": "<3.4",
"symfony/messenger": "<4.2",
"symfony/var-dumper": "<3.4"
"symfony/var-dumper": "<3.4",
"symfony/form": "<4.3"
},
"autoload": {
"psr-4": { "Symfony\\Bundle\\WebProfilerBundle\\": "" },
Expand Down
20 changes: 20 additions & 0 deletions src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php
Expand Up @@ -59,6 +59,26 @@ public function testGet()
$this->assertFalse($isHit);
}

public function testRecursiveGet()
{
if (isset($this->skippedTests[__FUNCTION__])) {
$this->markTestSkipped($this->skippedTests[__FUNCTION__]);
}

$cache = $this->createCachePool(0, __FUNCTION__);

$v = $cache->get('k1', function () use (&$counter, $cache) {
$v = $cache->get('k2', function () use (&$counter) { return ++$counter; });
$v = $cache->get('k2', function () use (&$counter) { return ++$counter; });

return $v;
});

$this->assertSame(1, $counter);
$this->assertSame(1, $v);
$this->assertSame(1, $cache->get('k2', function () { return 2; }));
}

public function testGetMetadata()
{
if (isset($this->skippedTests[__FUNCTION__])) {
Expand Down
Expand Up @@ -23,6 +23,7 @@ class PhpArrayAdapterTest extends AdapterTestCase
{
protected $skippedTests = [
'testGet' => 'PhpArrayAdapter is read-only.',
'testRecursiveGet' => 'PhpArrayAdapter is read-only.',
'testBasicUsage' => 'PhpArrayAdapter is read-only.',
'testBasicUsageWithLongKey' => 'PhpArrayAdapter is read-only.',
'testClear' => 'PhpArrayAdapter is read-only.',
Expand Down
12 changes: 7 additions & 5 deletions src/Symfony/Component/Cache/Traits/ContractsTrait.php
Expand Up @@ -32,6 +32,7 @@ trait ContractsTrait
}

private $callbackWrapper = [LockRegistry::class, 'compute'];
private $computing = [];

/**
* Wraps the callback passed to ->get() in a callable.
Expand Down Expand Up @@ -69,26 +70,27 @@ function (CacheItem $item, float $startTime, ?array &$metadata) {
CacheItem::class
);

return $this->contractsGet($pool, $key, function (CacheItem $item, bool &$save) use ($pool, $callback, $setMetadata, &$metadata) {
return $this->contractsGet($pool, $key, function (CacheItem $item, bool &$save) use ($pool, $callback, $setMetadata, &$metadata, $key) {
// don't wrap nor save recursive calls
if (null === $callbackWrapper = $this->callbackWrapper) {
if (isset($this->computing[$key])) {
$value = $callback($item, $save);
$save = false;

return $value;
}
$this->callbackWrapper = null;

$this->computing[$key] = $key;
$startTime = microtime(true);

try {
$value = $callbackWrapper($callback, $item, $save, $pool, function (CacheItem $item) use ($setMetadata, $startTime, &$metadata) {
$value = ($this->callbackWrapper)($callback, $item, $save, $pool, function (CacheItem $item) use ($setMetadata, $startTime, &$metadata) {
$setMetadata($item, $startTime, $metadata);
}, $this->logger ?? null);
$setMetadata($item, $startTime, $metadata);

return $value;
} finally {
$this->callbackWrapper = $callbackWrapper;
unset($this->computing[$key]);
}
}, $beta, $metadata, $this->logger ?? null);
}
Expand Down
Expand Up @@ -13,6 +13,7 @@

use Symfony\Component\DependencyInjection\ServiceSubscriberInterface as LegacyServiceSubscriberInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\Messenger\Handler\MessageSubscriberInterface;
use Symfony\Contracts\Service\ServiceSubscriberInterface;

/**
Expand Down Expand Up @@ -158,6 +159,13 @@ private function generateSignature(\ReflectionClass $class)
yield print_r($class->name::getSubscribedEvents(), true);
}

if (interface_exists(MessageSubscriberInterface::class, false) && $class->isSubclassOf(MessageSubscriberInterface::class)) {
yield MessageSubscriberInterface::class;
foreach ($class->name::getHandledMessages() as $key => $value) {
yield $key.print_r($value, true);
}
}

if (interface_exists(LegacyServiceSubscriberInterface::class, false) && $class->isSubclassOf(LegacyServiceSubscriberInterface::class)) {
yield LegacyServiceSubscriberInterface::class;
yield print_r([$class->name, 'getSubscribedServices'](), true);
Expand Down

0 comments on commit beb6036

Please sign in to comment.