Completed
Push — master ( 7c9eb0...a92430 )
by Thomas
13s
created

DisplayPrettyExceptionsAction   A

Complexity

Total Complexity 12

Size/Duplication

Total Lines 99
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 38
dl 0
loc 99
ccs 41
cts 41
cp 1
rs 10
c 0
b 0
f 0
wmc 12

5 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
A getOptionsClass() 0 3 1
A process() 0 37 5
A getSubscribedEvents() 0 4 1
A setLogger() 0 13 4
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the ekino Drupal Debug project.
7
 *
8
 * (c) ekino
9
 *
10
 * For the full copyright and license information, please view the LICENSE
11
 * file that was distributed with this source code.
12
 */
13
14
namespace Ekino\Drupal\Debug\Action\DisplayPrettyExceptions;
15
16
use Ekino\Drupal\Debug\Action\ActionWithOptionsInterface;
17
use Ekino\Drupal\Debug\Action\CompilerPassActionInterface;
18
use Ekino\Drupal\Debug\Action\EventSubscriberActionInterface;
19
use Ekino\Drupal\Debug\Exception\NotSupportedException;
20
use Ekino\Drupal\Debug\Kernel\Event\AfterAttachSyntheticEvent;
21
use Ekino\Drupal\Debug\Kernel\Event\DebugKernelEvents;
22
use Psr\Log\LoggerInterface;
23
use Symfony\Component\Debug\ExceptionHandler;
24
use Symfony\Component\DependencyInjection\ContainerBuilder;
25
use Symfony\Component\DependencyInjection\Definition;
26
use Symfony\Component\DependencyInjection\Reference;
27
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
28
use Symfony\Component\HttpKernel\EventListener\ExceptionListener;
29
30
class DisplayPrettyExceptionsAction implements CompilerPassActionInterface, EventSubscriberActionInterface, ActionWithOptionsInterface
31
{
32
    /**
33
     * @var string
34
     */
35
    const LOGGER_SERVICE_ID = 'ekino.drupal.debug.action.display_pretty_exceptions.logger';
36
37
    /**
38
     * @var DisplayPrettyExceptionsOptions
39
     */
40
    private $options;
41
42
    /**
43
     * {@inheritdoc}
44
     */
45 1
    public static function getSubscribedEvents(): array
46
    {
47
        return array(
48 1
            DebugKernelEvents::AFTER_ATTACH_SYNTHETIC => 'setLogger',
49
        );
50
    }
51
52
    /**
53
     * @param DisplayPrettyExceptionsOptions $options
54
     */
55 19
    public function __construct(DisplayPrettyExceptionsOptions $options)
56
    {
57 19
        $this->options = $options;
58 19
    }
59
60
    /**
61
     * {@inheritdoc}
62
     */
63 11
    public function process(ContainerBuilder $container): void
64
    {
65 11
        if (!$container->has('event_dispatcher')) {
66 1
            throw new NotSupportedException('The "event_dispatcher" service should already be set in the container.');
67
        }
68
69 10
        $eventDispatcherDefinition = $container->getDefinition('event_dispatcher');
70 10
        $eventDispatcherClass = $eventDispatcherDefinition->getClass();
71 10
        if (!\is_string($eventDispatcherClass)) {
72 1
            throw new NotSupportedException('The "event_dispatcher" service class should be a string.');
73
        }
74
75 9
        if (!(new \ReflectionClass($eventDispatcherClass))->implementsInterface(EventDispatcherInterface::class)) {
76 1
            throw new NotSupportedException(\sprintf('The "event_dispatcher" service class should implement the "%s" interface', EventDispatcherInterface::class));
77
        }
78
79 8
        $loggerReference = null;
80 8
        if ($this->options->getLogger() instanceof LoggerInterface) {
81 4
            $loggerDefinition = new Definition();
82 4
            $loggerDefinition->setSynthetic(true);
83
84 4
            $container->setDefinition(self::LOGGER_SERVICE_ID, $loggerDefinition);
85
86 4
            $loggerReference = new Reference(self::LOGGER_SERVICE_ID);
87
        }
88
89 8
        $eventDispatcherDefinition->addMethodCall('addSubscriber', array(
90 8
            new Definition(ExceptionListener::class, array(
91 8
                new Definition(ExceptionController::class, array(
92 8
                    new Definition(ExceptionHandler::class, array(
93 8
                        true,
94 8
                        $this->options->getCharset(),
95 8
                        $this->options->getFileLinkFormat(),
96
                    )),
97
                )),
98 8
                $loggerReference,
99
                true,
100
            )),
101
        ));
102 8
    }
103
104
    /**
105
     * @param AfterAttachSyntheticEvent $event
106
     */
107 4
    public function setLogger(AfterAttachSyntheticEvent $event): void
108
    {
109 4
        $container = $event->getContainer();
110
111 4
        $logger = $this->options->getLogger();
112 4
        if ($logger instanceof LoggerInterface) {
113 2
            if (!$container->has(self::LOGGER_SERVICE_ID)) {
114 1
                throw new \LogicException(\sprintf('The container should have a synthetic service with the id "%s".', self::LOGGER_SERVICE_ID));
115
            }
116
117 1
            $container->set(self::LOGGER_SERVICE_ID, $logger);
118 2
        } elseif ($container->has(self::LOGGER_SERVICE_ID)) {
119 1
            throw new \LogicException('The options should return a concrete logger.');
120
        }
121 2
    }
122
123
    /**
124
     * {@inheritdoc}
125
     */
126 3
    public static function getOptionsClass(): string
127
    {
128 3
        return DisplayPrettyExceptionsOptions::class;
129
    }
130
}
131