test_support-1.0.x-dev/tests/src/Traits/Support/WithoutEventSubscribers.php

tests/src/Traits/Support/WithoutEventSubscribers.php
<?php

namespace Drupal\Tests\test_support\Traits\Support;

use Drupal\Tests\test_support\Traits\Support\Decorators\DecoratedListener;
use Drupal\Tests\test_support\Traits\Support\Decorators\DecoratedListener as Listener;
use Illuminate\Support\Collection;
use PHPUnit\Framework\Assert;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

trait WithoutEventSubscribers
{
    /** @var Collection|null */
    private $ignoredSubscribers = null;

    /** @var Collection|null */
    private $ignoredEvents = null;

    /** @var string[]|class-string[] */
    private $deferredSubscribers = null;

    /**
     * Prevents event subscribers from acting when an event it's listening for is triggered.
     * Pass one or a list containing either class strings or service IDs.
     *
     * @code
     *     $this->withoutSubscribers('Drupal\node\Routing\RouteSubscriber')
     *     $this->withoutSubscribers('language.config_subscriber')
     *     $this->withoutSubscribers([
     *         'Drupal\node\Routing\RouteSubscriber',
     *         'language.config_subscriber',
     *     ]);
     *
     * @endcode
     *
     * @param string|class-string|string[]|class-string[] $listeners
     */
    public function withoutSubscribers($listeners = []): self
    {
        $this->getListeners()->when($listeners, function (Collection $collection, $listeners) {
            return $collection->filter(function (DecoratedListener $listener) use ($listeners): bool {
                return $listener->inList((array) $listeners);
            });
        })->whenEmpty(function (Collection $collection) use ($listeners) {
            $this->deferredSubscribers = collect($this->deferredSubscribers)->merge($listeners)->unique()->toArray();

            return $collection;
        })->each(function (Listener $listener) {
            $this->removeSubscriber($listener);
        });

        return $this;
    }

    /**
     * Define one or a list of event names to prevent listeners
     * acting when these events are triggered
     *
     * @code
     *     $this->withoutSubscribersForEvents(\Drupal\Core\Routing\RoutingEvents::ALTER)
     *     $this->withoutSubscribersForEvents('routing.route_finished')
     *     $this->withoutSubscribersForEvents([
     *         '\Drupal\Core\Routing\RoutingEvents::ALTER',
     *         'routing.route_finished',
     *     ]);
     *
     * @endcode
     *
     * @param string|class-string|string[]|class-string[] $eventNames
     */
    public function withoutSubscribersForEvents($eventNames): self
    {
        collect($eventNames)->each(function (string $event): void {
            $this->getListeners($event)->each(function (Listener $listener) use ($event): void {
                $this->removeSubscriber($listener, $event);
            });
        });

        return $this;
    }

    /**
     * @param string|class-string $listener
     * @param string|class-string|null $event
     */
    public function assertNotListening(string $listener, ?string $event = null): void
    {
        Assert::assertTrue(
            $this->getListeners($event)->filter(function (Listener $decoratedListener) use ($listener) {
                return $decoratedListener->inList((array) $listener);
            })->isEmpty()
        );
    }

    /**
     * @param string|class-string $listener
     * @param string|class-string|null $event
     */
    public function assertListening(string $listener, ?string $event = null): void
    {
        Assert::assertTrue(
            $this->getListeners($event)->filter(function (Listener $decoratedListener) use ($listener) {
                return $decoratedListener->inList((array) $listener);
            })->isNotEmpty()
        );
    }

    protected function enableModules(array $modules): void
    {
        parent::enableModules($modules);

        if ($this->ignoredSubscribers !== null) {
            $this->withoutSubscribers($this->ignoredSubscribers->keys()->toArray());
        }

        if ($this->deferredSubscribers !== null) {
            $this->withoutSubscribers($this->deferredSubscribers);
        }

        if ($this->ignoredEvents === null) {
            return;
        }

        $this->withoutSubscribersForEvents($this->ignoredEvents->keys()->toArray());
    }

    private function removeSubscriber(Listener $listener, ?string $event = null): self
    {
        /** @phpstan-ignore-next-line */
        $this->ignoredEvents = collect($this->ignoredEvents)->when($event, function (Collection $collection, string $event) {
            return $collection->put($event, $event);
        });

        $this->ignoredSubscribers = collect($this->ignoredSubscribers)->put($listener->getServiceId(), $listener);

        if ($listener->getOriginal() instanceof EventSubscriberInterface) {
            $this->container->get('event_dispatcher')->removeSubscriber($listener->getOriginal());
        }

        return $this;
    }

    private function getListeners(?string $event = null): Collection
    {
        $listeners = $this->container->get('event_dispatcher')->getListeners($event);

        return collect($listeners)->unless($event !== null, function (Collection $listeners) {
            return $listeners->values()->collapse();
        })->transform(function (array $listener) {
            $listener[2] = $this->resolveListenerServiceId($listener[0]);

            return $listener;
        })->mapInto(Listener::class);
    }

    private function resolveListenerServiceId(object $listener): ?string
    {
        if (property_exists($listener, '_serviceId')) {
            return $listener->_serviceId;
        }

        /** @phpstan-ignore-next-line */
        if ($this->container->has('Drupal\Core\DependencyInjection\ReverseContainer')) {
            /** @phpstan-ignore-next-line */
            return $this->container->get('Drupal\Core\DependencyInjection\ReverseContainer')->getId($listener);
        }

        /** @phpstan-ignore-next-line */
        $serviceMap = $this->container->get('kernel')->getServiceIdMapping();

        /** @phpstan-ignore-next-line */
        $serviceHash = $this->container->generateServiceIdHash($listener);

        return $serviceMap[$serviceHash] ?? null;
    }
}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc