Skip to content

Commit

Permalink
Merge pull request #92 from nextras/symfony_bundle
Browse files Browse the repository at this point in the history
Add SymfonyBundle
  • Loading branch information
hrach committed Apr 19, 2020
2 parents f2091dd + 584dee6 commit 8deddf6
Show file tree
Hide file tree
Showing 13 changed files with 569 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,8 @@ parameters:
- throwWrongModifierException
Nextras\Dbal\Drivers\Sqlsrv\SqlsrvDriver:
- throwErrors

ignoreErrors:
-
message: '~Call to an undefined method .+::children\(\)\.~'
path: "src/Bridges/SymfonyBundle/DependencyInjection/Configuration.php"
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ before_install:
- mysql -e 'CREATE DATABASE nextras_dbal_test;'
- mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql
- mysql -u root -e "SET PASSWORD FOR 'root'@'localhost' = PASSWORD('')"
- if [ "$TRAVIS_PHP_VERSION" == "7.1" ]; then rm composer.json && mv composer_php71.json composer.json; fi

install:
- travis_retry composer update --no-interaction --prefer-dist --no-progress
Expand Down
3 changes: 3 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
"nette/neon": "~3.0",
"phpstan/phpstan": "0.12.18",
"phpstan/phpstan-deprecation-rules": "0.12.2",
"symfony/config": "~5.0",
"symfony/dependency-injection": "~5.0",
"symfony/http-kernel": "~5.0",
"tracy/tracy": "~2.7"
},
"autoload": {
Expand Down
20 changes: 20 additions & 0 deletions composer_php71.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"type": "library",
"require-dev": {
"php": ">=7.1",
"mockery/mockery": "~1.3.0",
"nette/tester": "~2.3.1",
"nette/caching": "~3.0",
"nette/di": "~3.0",
"nette/utils": "~3.0",
"nette/finder": "~2.5",
"nette/neon": "~3.0",
"phpstan/phpstan": "0.12.18",
"phpstan/phpstan-deprecation-rules": "0.12.2",
"tracy/tracy": "~2.7"
},
"autoload": {
"psr-4": { "Nextras\\Dbal\\": "src/" },
"classmap": ["src/exceptions.php"]
}
}
5 changes: 5 additions & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@ Supported platforms:
- **PostgreSQL** via `pgsql` extension,
- **MS SQL Server** via `sqlsrv` extension.

Integrations:
- Symfony Bundle
- Nette DI Extension
- Tracy Panel

### Installation

Use composer:
Expand Down
152 changes: 152 additions & 0 deletions src/Bridges/SymfonyBundle/DataCollector/QueryDataCollector.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
<?php declare(strict_types = 1);

/**
* This file is part of the Nextras\Dbal library.
* @license MIT
* @link https://github.com/nextras/dbal
*/

namespace Nextras\Dbal\Bridges\SymfonyBundle\DataCollector;

use Nextras\Dbal\Bridges\NetteTracy\ConnectionPanel;
use Nextras\Dbal\DriverException;
use Nextras\Dbal\IConnection;
use Nextras\Dbal\ILogger;
use Nextras\Dbal\Platforms\IPlatform;
use Nextras\Dbal\Result\Result;
use Nextras\Dbal\Utils\SqlHighlighter;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\DataCollector\DataCollector;
use function strlen;
use function substr;
use function ucfirst;
use function uniqid;


class QueryDataCollector extends DataCollector implements ILogger
{
/** @var IConnection */
private $connection;

/** @var bool */
private $explain;

/**
* @var array
* @phpstan-var array<array{string, float, ?int}>
*/
private $queries = [];


public function __construct(IConnection $connection, bool $explain, string $name)
{
$this->connection = $connection;
$this->explain = $explain && $connection->getPlatform()->isSupported(IPlatform::SUPPORT_QUERY_EXPLAIN);
$this->data['name'] = $name;
$this->reset();
}


public function getName()
{
return $this->data['name'];
}


public function collect(Request $request, Response $response, \Throwable $exception = null): void
{
foreach ($this->queries as [$sqlQuery, $timeTaken, $rowsCount]) {
$row = [
'uniqId' => uniqid('nextras-dbal-sql-'),
'sql' => SqlHighlighter::highlight($sqlQuery),
'rowsCount' => $rowsCount,
'timeTaken' => $timeTaken,
'explain' => null,
];

try {
if ($this->explain) {
$row['explain'] = $this->connection->getDriver()->query('EXPLAIN ' . $sqlQuery)->fetchAll();
}
} catch (\Throwable $e) {
$row['explain'] = null;
$row['rowsCount'] = null; // rows count is also irrelevant
}

$this->data['queries'][] = $row;
}
}


public function reset(): void
{
$this->queries = [];
$this->data = [
'name' => $this->data['name'] ?? '',
'count' => 0,
'time' => 0.0,
'queries' => [],
'whitespaceExplain' => $this->connection->getPlatform()->isSupported(IPlatform::SUPPORT_WHITESPACE_EXPLAIN),
];
}


public function getTitle(): string
{
return ucfirst(substr($this->getName(), strlen('nextras_dbal.'), -strlen('.query_data_collector')));
}


public function getQueryCount(): int
{
return $this->data['count'];
}


public function getTotalTime(): float
{
return $this->data['time'];
}


/**
* @return array<mixed>
*/
public function getQueries(): array
{
return $this->data['queries'];
}


public function getWhitespaceExplain(): bool
{
return $this->data['whitespaceExplain'];
}


public function onConnect(): void
{
}


public function onDisconnect(): void
{
}


public function onQuery(string $sqlQuery, float $timeTaken, ?Result $result, ?DriverException $exception): void
{
$this->data['count']++;
if ($this->data['count'] > 100) {
return;
}

$this->data['time'] += $timeTaken;
$this->queries[] = [
$sqlQuery,
$timeTaken,
$result ? $result->count() : null,
];
}
}
63 changes: 63 additions & 0 deletions src/Bridges/SymfonyBundle/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php declare(strict_types = 1);

/**
* This file is part of the Nextras\Dbal library.
* @license MIT
* @link https://github.com/nextras/dbal
*/

namespace Nextras\Dbal\Bridges\SymfonyBundle\DependencyInjection;

use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
use function array_key_exists;
use function is_array;


class Configuration implements ConfigurationInterface
{
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder('nextras_dbal');

// @formatter:off
$treeBuilder->getRootNode()
->beforeNormalization()
->ifTrue(static function ($v) {
return is_array($v) && !array_key_exists('connections', $v);
})
->then(static function ($v) {
return [
'connections' => ['default' => $v],
'default_connection' => 'default',
];
})
->end()
->children()
->scalarNode('default_connection')
->defaultValue('default')
->end()
->arrayNode('connections')
->useAttributeAsKey('name')
->arrayPrototype()
->ignoreExtraKeys(false)
->children()
->scalarNode('driver')
->isRequired()
->cannotBeEmpty()
->end()
->booleanNode('profiler')
->defaultTrue()
->end()
->booleanNode('profilerExplain')
->defaultTrue()
->end()
->end()
->end()
->end()
->end();
// @formatter:on

return $treeBuilder;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php declare(strict_types = 1);

/**
* This file is part of the Nextras\Dbal library.
* @license MIT
* @link https://github.com/nextras/dbal
*/

namespace Nextras\Dbal\Bridges\SymfonyBundle\DependencyInjection;

use Nextras\Dbal\Bridges\SymfonyBundle\DataCollector\QueryDataCollector;
use Nextras\Dbal\Connection;
use Nextras\Dbal\IConnection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;


class NextrasDbalExtension extends Extension
{
/**
* @param array<mixed> $configs
*/
public function load(array $configs, ContainerBuilder $container): void
{
$config = $this->processConfiguration(new Configuration(), $configs);

$defaultConnectionName = $config['default_connection'];
foreach ($config['connections'] as $name => $connectionConfig) {
$profiler = $connectionConfig['profiler'];
$explain = $connectionConfig['profilerExplain'];
$this->loadConnection(
$container,
$name,
$connectionConfig,
$name === $defaultConnectionName,
$profiler,
$explain
);
}
}


/**
* @param array<mixed> $config
*/
private function loadConnection(
ContainerBuilder $container,
string $name,
array $config,
bool $isDefault,
bool $profiler,
bool $explain
): void
{
$connectionDefinition = new Definition(Connection::class);
$connectionDefinition->setArgument('$config', $config);
$connectionDefinition->setPublic(true);

$container->addDefinitions([
"nextras_dbal.$name.connection" => $connectionDefinition,
]);

if ($isDefault) {
$container->setAlias(IConnection::class, "nextras_dbal.$name.connection")
->setPublic(true);
}

if ($profiler) {
$collectorName = "nextras_dbal.$name.query_data_collector";
$collectorDefinition = new Definition(QueryDataCollector::class);
$collectorDefinition->setArgument('$connection', new Reference("nextras_dbal.$name.connection"));
$collectorDefinition->setArgument('$explain', $explain);
$collectorDefinition->setArgument('$name', $collectorName);
$collectorDefinition->addTag('data_collector', [
'template' => '@NextrasDbal/DataCollector/template.html.twig',
'id' => $collectorName,
]);

$container->addDefinitions([
$collectorName => $collectorDefinition,
]);

$connectionDefinition->addMethodCall('addLogger', [new Reference($collectorName)]);
}
}
}
16 changes: 16 additions & 0 deletions src/Bridges/SymfonyBundle/NextrasDbalBundle.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?php declare(strict_types = 1);

/**
* This file is part of the Nextras\Dbal library.
* @license MIT
* @link https://github.com/nextras/dbal
*/

namespace Nextras\Dbal\Bridges\SymfonyBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;


class NextrasDbalBundle extends Bundle
{
}
6 changes: 6 additions & 0 deletions src/Bridges/SymfonyBundle/Resources/config/nextras_dbal.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
nextras_dbal:
driver:
host: 127.0.0.1
username:
password:
database:
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit 8deddf6

Please sign in to comment.