Skip to content

Show better message when SQLite is not enabled #431

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
3 changes: 2 additions & 1 deletion app/config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ services:
# the list of events listened by that class.
# See http://symfony.com/doc/current/event_dispatcher.html#creating-an-event-subscriber
app.console_subscriber:
class: AppBundle\EventListener\ConsoleEventSubscriber
class: AppBundle\EventListener\CheckSQLiteEventSubscriber
arguments: ['@doctrine.orm.entity_manager']
tags:
- { name: kernel.event_subscriber }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,14 @@

namespace AppBundle\EventListener;

use Doctrine\DBAL\Exception\DriverException;
use Doctrine\ORM\EntityManager;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\Console\Event\ConsoleExceptionEvent;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\KernelEvents;

/**
* This application uses by default an SQLite database to store its information.
Expand All @@ -24,8 +28,23 @@
*
* @author Javier Eguiluz <[email protected]>
*/
class ConsoleEventSubscriber implements EventSubscriberInterface
class CheckSQLiteEventSubscriber implements EventSubscriberInterface
{
/**
* @var EntityManager
*/
private $entityManager;

/**
* CheckSQLiteEventSubscriber constructor.
*
* @param EntityManager $entityManager
*/
public function __construct(EntityManager $entityManager)
{
$this->entityManager = $entityManager;
}

// Event Subscribers must define this method to declare the events they
// listen to. You can listen to several events, execute more than one method
// for each event and set the priority of each event too.
Expand All @@ -36,6 +55,8 @@ public static function getSubscribedEvents()
// Exceptions are one of the events defined by the Console. See the
// rest here: http://symfony.com/doc/current/components/console/events.html
ConsoleEvents::EXCEPTION => 'handleDatabaseExceptions',
// See: http://api.symfony.com/3.2/Symfony/Component/HttpKernel/KernelEvents.html
KernelEvents::EXCEPTION => 'onKernelException',
];
}

Expand All @@ -51,10 +72,43 @@ public function handleDatabaseExceptions(ConsoleExceptionEvent $event)
$commandNames = ['doctrine:fixtures:load', 'doctrine:database:create', 'doctrine:schema:create', 'doctrine:database:drop'];

if (in_array($event->getCommand()->getName(), $commandNames)) {
if (!extension_loaded('sqlite3')) {
if ($this->isSQLitePlatform() && !extension_loaded('sqlite3')) {
$io = new SymfonyStyle($event->getInput(), $event->getOutput());
$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.');
}
}
}

/**
* This method is triggered when kernel exception occurs. And checks if sqlite extension is enabled.
*
* @param GetResponseForExceptionEvent $event
*/
public function onKernelException(GetResponseForExceptionEvent $event)
{
$exception = $event->getException();
// Since any exception thrown during a Twig template rendering is wrapped in a Twig_Error_Runtime.
// We must get the original exception.
$previousException = $exception->getPrevious();

// Driver exception may happen in controller or in twig template rendering
$isDriverException = ($exception instanceof DriverException || $previousException instanceof DriverException);
Copy link
Contributor

@voronkovich voronkovich Jan 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should make sure that a connection is configured to use an sqlite driver because it can be an error with another one (mysql, postgres and etc.).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, you are totally correct :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@uikolas, you could use a platform name:

$entityManager->getConnection()->getDatabasePlatform()->getName() === 'sqlite'

See https://github.com/doctrine/dbal/blob/master/lib/Doctrine/DBAL/Platforms/SqlitePlatform.php#L511


// Check if SQLite is enabled
if ($isDriverException && $this->isSQLitePlatform() && !extension_loaded('sqlite3')) {
$event->setException(new \Exception('PHP extension "sqlite3" must be enabled because, by default, the Symfony Demo application uses SQLite to store its information.'));
}
}

/**
* Check if demo application is configured to use SQLite as database.
*
* @return bool
*/
private function isSQLitePlatform()
{
$databasePlatform = $this->entityManager->getConnection()->getDatabasePlatform();

return $databasePlatform ? $databasePlatform->getName() === 'sqlite' : false;
}
}