Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,18 @@ php client.phar <project-directory> execute <base64-code>
php client.phar <project-directory> execute-stream <base64-code>
```

Available options:

- `--query-log=<bool>`: enable database query collection for `execute` and
`execute-stream`. Accepts `true`/`false`, `1`/`0`, `on`/`off`, and
`yes`/`no`. Query logging is disabled by default: no query listeners are
attached to the project's database, and every `queries` field in the output
is an empty array.

```bash
php client.phar /path/to/project execute "$code" --query-log=true
```

## Check Project Info

`info` reports the detected project type, project version, and PHP version:
Expand Down
2 changes: 2 additions & 0 deletions index.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@

$customLoader = Cli::getArgument('loader');
try {
QueryCollector::enable(filter_var(Cli::getArgument('query-log'), FILTER_VALIDATE_BOOL));

$loader = Loader::load($arguments[1], $customLoader ?: null);

if ($loader === null) {
Expand Down
25 changes: 25 additions & 0 deletions src/Database/QueryCollector.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

class QueryCollector
{
protected static bool $enabled = false;

/** @var QueryProviderInterface[] */
protected static array $providers = [];

Expand All @@ -13,13 +15,28 @@ class QueryCollector

protected static array $errors = [];

public static function enable(bool $enabled = true): void
{
self::$enabled = $enabled;
}

public static function isEnabled(): bool
{
return self::$enabled;
}

public static function register(QueryProviderInterface $provider): void
{
if (! self::$enabled) {
return;
}

self::$providers[] = $provider;
}

public static function reset(): void
{
self::$enabled = false;
self::$providers = [];
self::$queries = [];
self::$allCapturedQueries = [];
Expand All @@ -28,6 +45,10 @@ public static function reset(): void

public static function start(): void
{
if (! self::$enabled) {
return;
}

self::$queries = [];
self::$errors = [];

Expand All @@ -42,6 +63,10 @@ public static function start(): void

public static function stop(): array
{
if (! self::$enabled) {
return [];
}

self::$queries = [];

foreach (self::$providers as $provider) {
Expand Down
41 changes: 41 additions & 0 deletions tests/CliTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -65,4 +65,45 @@ public function test_execute_reports_runtime_errors_with_queries_array(): void
$this->assertArrayHasKey('queries', $data);
$this->assertIsArray($data['queries']);
}

/** @dataProvider provideQueryLogArguments */
public function test_execute_keeps_queries_key_with_query_log_argument(string $argument): void
{
$code = base64_encode('return 1;');
$command = sprintf(
'%s %s %s %s %s',
escapeshellarg(PHP_BINARY),
escapeshellarg(__DIR__.'/../index.php'),
escapeshellarg(__DIR__.'/..'),
'execute',
escapeshellarg($code)
);

if ($argument !== '') {
$command .= ' '.escapeshellarg($argument);
}

exec($command, $output, $exitCode);

$this->assertSame(0, $exitCode);
$rawOutput = implode(PHP_EOL, $output);
$this->assertStringStartsWith('TWEAKPHP_RESULT:', $rawOutput);

$data = json_decode(substr($rawOutput, strlen('TWEAKPHP_RESULT:')), true);

$this->assertIsArray($data);
$this->assertArrayHasKey('queries', $data);
$this->assertSame([], $data['queries']);
$this->assertArrayHasKey('queries', $data['output'][0]);
$this->assertSame([], $data['output'][0]['queries']);
}

public function provideQueryLogArguments(): array
{
return [
'no argument' => [''],
'query log disabled' => ['--query-log=false'],
'query log enabled' => ['--query-log=true'],
];
}
}
49 changes: 49 additions & 0 deletions tests/QueryCollectorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ class QueryCollectorTest extends TestCase
protected function setUp(): void
{
QueryCollector::reset();
QueryCollector::enable(true);
}

public function test_query_collector_with_laravel_db()
Expand Down Expand Up @@ -283,5 +284,53 @@ public function test_query_collector_get_captured_queries_accumulates_across_sta
$this->assertSame('SELECT * FROM users WHERE id = 1', $allQueries[0]['sql']);
$this->assertSame('SELECT * FROM users WHERE id = 999', $allQueries[1]['sql']);
}

public function test_query_collector_is_disabled_by_default(): void
{
QueryCollector::reset();

$this->assertFalse(QueryCollector::isEnabled());
}

public function test_query_collector_ignores_providers_when_disabled(): void
{
QueryCollector::enable(false);

$provider = $this->createMock(QueryProviderInterface::class);
$provider->expects($this->never())->method('start');
$provider->expects($this->never())->method('stop');

QueryCollector::register($provider);
QueryCollector::start();

$this->assertSame([], QueryCollector::stop());
$this->assertSame([], QueryCollector::errors());
$this->assertSame([], QueryCollector::getCapturedQueries());
}

public function test_query_collector_ignores_registration_from_before_enable(): void
{
QueryCollector::enable(false);

$ignoredProvider = $this->createMock(QueryProviderInterface::class);
$ignoredProvider->expects($this->never())->method('start');
$ignoredProvider->expects($this->never())->method('stop');
QueryCollector::register($ignoredProvider);

QueryCollector::enable(true);

$provider = $this->createMock(QueryProviderInterface::class);
$provider->expects($this->once())->method('start');
$provider->expects($this->once())->method('stop')->willReturn([
['sql' => 'SELECT 1'],
]);
QueryCollector::register($provider);

QueryCollector::start();

$this->assertSame([
['sql' => 'SELECT 1'],
], QueryCollector::stop());
}
}
}
1 change: 1 addition & 0 deletions tests/TinkerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ protected function doExecuteStreaming(string $code, int $index, callable $onEven
};
$provider = $this->createMock(QueryProviderInterface::class);
$provider->method('stop')->willThrowException(new \RuntimeException('query collection failed'));
QueryCollector::enable(true);
QueryCollector::register($provider);
$events = [];

Expand Down
Loading