CheckRequirementsSubscriber::getSubscribedEvents()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 10
rs 9.9332
c 0
b 0
f 0
cc 1
nc 1
nop 0
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the Explicit Architecture POC,
7
 * which is created on top of the Symfony Demo application.
8
 *
9
 * (c) Herberto Graça <[email protected]>
10
 *
11
 * For the full copyright and license information, please view the LICENSE
12
 * file that was distributed with this source code.
13
 */
14
15
namespace Acme\App\Presentation\Console\EventSubscriber;
16
17
use Doctrine\DBAL\Exception\DriverException;
18
use Doctrine\ORM\EntityManagerInterface;
19
use Symfony\Component\Console\ConsoleEvents;
20
use Symfony\Component\Console\Event\ConsoleErrorEvent;
21
use Symfony\Component\Console\Style\SymfonyStyle;
22
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
23
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
24
use Symfony\Component\HttpKernel\KernelEvents;
25
26
/**
27
 * This application uses by default an SQLite database to store its information.
28
 * That's why the 'sqlite3' extension must be enabled in PHP. This event
29
 * subscriber listens to console events and in case of an exception caused by
30
 * a disabled 'sqlite3' extension, it displays a meaningful error message.
31
 *
32
 * @author Javier Eguiluz <[email protected]>
33
 */
34
class CheckRequirementsSubscriber implements EventSubscriberInterface
35
{
36
    /**
37
     * @var EntityManagerInterface
38
     */
39
    private $entityManager;
40
41
    public function __construct(EntityManagerInterface $entityManager)
42
    {
43
        $this->entityManager = $entityManager;
44
    }
45
46
    // Event Subscribers must define this method to declare the events they
47
    // listen to. You can listen to several events, execute more than one method
48
    // for each event and set the priority of each event too.
49
    // See https://symfony.com/doc/current/event_dispatcher.html#creating-an-event-subscriber
50
    public static function getSubscribedEvents(): array
51
    {
52
        return [
53
            // Errors are one of the events defined by the Console. See the
54
            // rest here: https://symfony.com/doc/current/components/console/events.html
55
            ConsoleEvents::ERROR => 'handleConsoleError',
56
            // See: http://api.symfony.com/master/Symfony/Component/HttpKernel/KernelEvents.html
57
            KernelEvents::EXCEPTION => 'handleKernelException',
58
        ];
59
    }
60
61
    /**
62
     * This method checks if there has been an error in a command related to
63
     * the database and then, it checks if the 'sqlite3' PHP extension is enabled
64
     * or not to display a better error message.
65
     *
66
     * @throws \Doctrine\DBAL\DBALException
67
     */
68
    public function handleConsoleError(ConsoleErrorEvent $event): void
69
    {
70
        $commandNames = ['doctrine:fixtures:load', 'doctrine:database:create', 'doctrine:schema:create', 'doctrine:database:drop'];
71
72
        if ($event->getCommand() && \in_array($event->getCommand()->getName(), $commandNames, true)) {
73
            if ($this->isSQLitePlatform() && !\extension_loaded('sqlite3')) {
74
                $io = new SymfonyStyle($event->getInput(), $event->getOutput());
75
                $io->error('This command requires to have the "sqlite3" PHP extension enabled because, by default, the Symfony Demo application uses SQLite to store its information.');
76
            }
77
        }
78
    }
79
80
    /**
81
     * This method checks if the triggered exception is related to the database
82
     * and then, it checks if the required 'sqlite3' PHP extension is enabled.
83
     *
84
     * @throws \Doctrine\DBAL\DBALException
85
     */
86
    public function handleKernelException(GetResponseForExceptionEvent $event): void
87
    {
88
        $exception = $event->getException();
0 ignored issues
show
Deprecated Code introduced by
The method Symfony\Component\HttpKe...onEvent::getException() has been deprecated with message: since Symfony 4.4, use getThrowable instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
89
        // Since any exception thrown during a Twig template rendering is wrapped
90
        // in a Twig_Error_Runtime, we must get the original exception.
91
        $previousException = $exception->getPrevious();
92
93
        // Driver exception may happen in controller or in twig template rendering
94
        $isDriverException = ($exception instanceof DriverException || $previousException instanceof DriverException);
95
96
        // Check if SQLite is enabled
97
        if ($isDriverException && $this->isSQLitePlatform() && !extension_loaded('sqlite3')) {
98
            $event->setException(new \Exception('PHP extension "sqlite3" must be enabled because, by default, the Symfony Demo application uses SQLite to store its information.'));
0 ignored issues
show
Deprecated Code introduced by
The method Symfony\Component\HttpKe...onEvent::setException() has been deprecated with message: since Symfony 4.4, use setThrowable instead

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
99
        }
100
    }
101
102
    /**
103
     * Checks if the application is using SQLite as its database.
104
     *
105
     * @throws \Doctrine\DBAL\DBALException
106
     */
107
    private function isSQLitePlatform(): bool
108
    {
109
        $databasePlatform = $this->entityManager->getConnection()->getDatabasePlatform();
110
111
        return $databasePlatform ? $databasePlatform->getName() === 'sqlite' : false;
112
    }
113
}
114