Skip to content

Commit 1ac0bfa

Browse files
committed
Added WordPress Database Handler with unit tests.
1 parent 2b24ee4 commit 1ac0bfa

File tree

3 files changed

+145
-1
lines changed

3 files changed

+145
-1
lines changed

plugins/wpgraphql-logging/src/Logger/Database/DatabaseEntity.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,6 @@ public static function get_schema(): string {
191191

192192
/**
193193
* Creates the logging table in the database.
194-
*
195194
*/
196195
public static function create_table(): void {
197196
require_once ABSPATH . 'wp-admin/includes/upgrade.php';
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace WPGraphQL\Logging\Logger\Handlers;
6+
7+
use Monolog\Handler\AbstractProcessingHandler;
8+
use Monolog\LogRecord;
9+
use Throwable;
10+
use WPGraphQL\Logging\Logger\Database\DatabaseEntity;
11+
12+
/**
13+
* WordPress Database Handler for Monolog
14+
*
15+
* @package WPGraphQL\Logging
16+
*
17+
* @since 0.0.1
18+
*/
19+
class WordPressDatabaseHandler extends AbstractProcessingHandler {
20+
/**
21+
* Writes the log record to the database.
22+
*
23+
* This is the core method of the handler. It gets called by Monolog
24+
* for each log record that needs to be processed.
25+
*
26+
* @param \Monolog\LogRecord $record The log record containing all log data.
27+
*/
28+
protected function write( LogRecord $record ): void {
29+
try {
30+
$name = $record->level->getName();
31+
$entity = DatabaseEntity::create(
32+
$record->channel,
33+
$record->level->value,
34+
(is_string($name) && $name !== '') ? $name : 'INFO',
35+
$record->message,
36+
$record->context ?: [],
37+
$record->extra ?: []
38+
);
39+
40+
$entity->save();
41+
} catch ( Throwable $e ) {
42+
error_log( 'Error logging to WordPress database: ' . $e->getMessage() ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
43+
}
44+
}
45+
}
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace WPGraphQL\Logging\Tests\Handlers;
6+
7+
use lucatume\WPBrowser\TestCase\WPTestCase;
8+
use Monolog\Level;
9+
use Monolog\LogRecord;
10+
use DateTimeImmutable;
11+
use WPGraphQL\Logging\Logger\Database\DatabaseEntity;
12+
use WPGraphQL\Logging\Logger\Handlers\WordPressDatabaseHandler;
13+
14+
/**
15+
* Class WordPressDatabaseHandlerTest
16+
*
17+
* Tests for the WordPressDatabaseHandler class.
18+
*/
19+
class WordPressDatabaseHandlerTest extends WPTestCase
20+
{
21+
protected LogRecord $record;
22+
23+
protected array $log_data;
24+
25+
/**
26+
* Set up the test environment.
27+
*/
28+
public function setUp(): void
29+
{
30+
parent::setUp();
31+
DatabaseEntity::create_table();
32+
33+
// Setup test record data.
34+
$this->log_data = [
35+
'channel' => 'wpgraphql_logging',
36+
'level' => Level::Info,
37+
'message' => 'Test log message',
38+
'context' => ['test_key' => 'test_value'],
39+
'extra' => ['extra_key' => 'extra_value'],
40+
'datetime' => new DateTimeImmutable(),
41+
];
42+
43+
// Create a LogRecord instance for testing.
44+
$this->record = new LogRecord(
45+
$this->log_data['datetime'],
46+
$this->log_data['channel'],
47+
$this->log_data['level'],
48+
$this->log_data['message'],
49+
$this->log_data['context'],
50+
$this->log_data['extra']
51+
);
52+
}
53+
54+
public function tearDown(): void
55+
{
56+
DatabaseEntity::drop_table();
57+
parent::tearDown();
58+
}
59+
60+
public function test_write_method_saves_log_to_database(): void
61+
{
62+
global $wpdb;
63+
64+
// 3. Create an instance of the handler and call the write method.
65+
$handler = new WordPressDatabaseHandler();
66+
$handler->handle($this->record);
67+
$log_data = $this->log_data;
68+
69+
// 4. Verify the data was saved correctly in the database.
70+
$table_name = DatabaseEntity::get_table_name();
71+
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
72+
$saved_row = $wpdb->get_row("SELECT * FROM {$table_name} ORDER BY id DESC LIMIT 1", ARRAY_A);
73+
74+
$this->assertNotNull($saved_row, 'A log entry should have been created in the database.');
75+
$this->assertEquals($log_data['channel'], $saved_row['channel']);
76+
$this->assertEquals($log_data['level']->value, $saved_row['level']);
77+
$this->assertEquals($log_data['level']->getName(), $saved_row['level_name']);
78+
$this->assertEquals($log_data['message'], $saved_row['message']);
79+
80+
// Compare the JSON-decoded context and extra fields.
81+
$this->assertEquals($log_data['context'], json_decode($saved_row['context'], true));
82+
$this->assertEquals($log_data['extra'], json_decode($saved_row['extra'], true));
83+
}
84+
85+
public function test_write_method_handles_exceptions_gracefully(): void
86+
{
87+
// Drop the table to force the save operation to fail.
88+
DatabaseEntity::drop_table();
89+
global $wpdb;
90+
$wpdb->flush();
91+
92+
$handler = new WordPressDatabaseHandler();
93+
try {
94+
$handler->handle($this->record);
95+
$this->assertTrue(true, 'The handler should catch the exception and not crash.');
96+
} catch (\Throwable $e) {
97+
$this->fail('The handler should have caught the exception. Error: ' . $e->getMessage());
98+
}
99+
}
100+
}

0 commit comments

Comments
 (0)