Skip to content

Commit 9b13a41

Browse files
authored
Merge pull request #856 from cakephp/ref-deprecation-panel
Update deprecations panel to use new error handlers
2 parents ce564ba + 3b741ae commit 9b13a41

5 files changed

Lines changed: 67 additions & 58 deletions

File tree

.github/workflows/ci.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,13 @@ jobs:
1515
strategy:
1616
fail-fast: false
1717
matrix:
18-
php-version: ['7.2', '8.0']
18+
php-version: ['7.4', '8.0']
1919
db-type: [mysql, pgsql, sqlite]
2020
prefer-lowest: ['']
2121
include:
2222
- php-version: '8.1'
2323
db-type: 'sqlite'
24-
- php-version: '7.2'
24+
- php-version: '7.4'
2525
db-type: 'sqlite'
2626
prefer-lowest: 'prefer-lowest'
2727

composer.json

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
},
2525
"require": {
2626
"php": ">=7.2",
27-
"cakephp/cakephp": "^4.3.0",
27+
"cakephp/cakephp": "dev-4.next as 4.4.0",
2828
"cakephp/chronos": "^2.0",
2929
"composer/composer": "^1.3 | ^2.0",
3030
"jdorn/sql-formatter": "^1.2"
@@ -58,5 +58,10 @@
5858
"psalm": "psalm.phar --show-info=false",
5959
"psalm-setup": "cp composer.json composer.backup && composer require --dev psalm/phar:^4.10 && mv composer.backup composer.json"
6060
},
61-
"prefer-stable": true
61+
"prefer-stable": true,
62+
"config": {
63+
"allow-plugins": {
64+
"dealerdirect/phpcodesniffer-composer-installer": true
65+
}
66+
}
6267
}

src/Panel/DeprecationsPanel.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,6 @@ protected function _prepare()
5959
foreach ($errors as $error) {
6060
$file = $error['file'];
6161
$line = $error['line'];
62-
if (isset($error['context']['frame'])) {
63-
$file = $error['context']['frame']['file'];
64-
$line = $error['context']['frame']['line'];
65-
}
6662

6763
$errorData = [
6864
'file' => $file,

src/Plugin.php

Lines changed: 24 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
use Cake\Core\BasePlugin;
2020
use Cake\Core\Configure;
2121
use Cake\Core\PluginApplicationInterface;
22+
use Cake\Error\PhpError;
23+
use Cake\Event\EventInterface;
2224
use Cake\Event\EventManager;
2325
use Cake\Http\MiddlewareQueue;
2426
use DebugKit\Command\BenchmarkCommand;
@@ -50,7 +52,6 @@ public function bootstrap(PluginApplicationInterface $app): void
5052
}
5153

5254
$this->service = $service;
53-
5455
$this->setDeprecationHandler($service);
5556

5657
// will load `config/bootstrap.php`.
@@ -92,40 +93,30 @@ public function console(CommandCollection $commands): CommandCollection
9293
public function setDeprecationHandler($service)
9394
{
9495
if (!empty($service->getConfig('panels')['DebugKit.Deprecations'])) {
95-
$previousHandler = set_error_handler(
96-
function ($code, $message, $file, $line, $context = null) use (&$previousHandler) {
97-
if ($code == E_USER_DEPRECATED || $code == E_DEPRECATED) {
98-
// In PHP 8.0+ the $context variable has been removed from the set_error_handler callback
99-
// Therefore we need to fetch the correct file and line string ourselves
100-
if (PHP_VERSION_ID >= 80000) {
101-
$trace = debug_backtrace();
102-
foreach ($trace as $idx => $traceEntry) {
103-
if ($traceEntry['function'] !== 'deprecationWarning') {
104-
continue;
105-
}
106-
$offset = 1;
107-
// ['args'][1] refers to index of $stackFrame argument in deprecationWarning()
108-
if (isset($traceEntry['args'][1])) {
109-
$offset = $traceEntry['args'][1];
110-
}
111-
$file = $trace[$idx + $offset]['file'];
112-
$line = $trace[$idx + $offset]['line'];
113-
break;
114-
}
115-
}
116-
DeprecationsPanel::addDeprecatedError(compact('code', 'message', 'file', 'line', 'context'));
117-
118-
return;
119-
}
120-
if ($previousHandler) {
121-
$context['_trace_frame_offset'] = 1;
122-
123-
return $previousHandler($code, $message, $file, $line, $context);
124-
}
96+
EventManager::instance()->on('Error.beforeRender', function (EventInterface $event, PhpError $error) {
97+
$code = $error->getCode();
98+
if ($code !== E_USER_DEPRECATED && $code !== E_DEPRECATED) {
99+
return;
100+
}
101+
$file = $error->getFile();
102+
$line = $error->getLine();
125103

126-
return false;
104+
// Extract the line/file from the message as deprecationWarning
105+
// will calculate the application frame when generating the message.
106+
preg_match('/\\n([^\n,]+?), line: (\d+)\\n/', $error->getMessage(), $matches);
107+
if ($matches) {
108+
$file = $matches[1];
109+
$line = $matches[2];
127110
}
128-
);
111+
112+
DeprecationsPanel::addDeprecatedError([
113+
'code' => $code,
114+
'message' => $error->getMessage(),
115+
'file' => $file,
116+
'line' => $line,
117+
]);
118+
$event->stopPropagation();
119+
});
129120
}
130121
}
131122
}

tests/TestCase/PluginTest.php

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*/
1515
namespace DebugKit\Test\TestCase;
1616

17+
use Cake\Error\PhpError;
1718
use Cake\Event\Event;
1819
use Cake\Event\EventManager;
1920
use Cake\TestSuite\TestCase;
@@ -37,28 +38,44 @@ public function testSetDeprecationHandler()
3738
$service = new ToolbarService(new EventManager(), []);
3839
$plugin = new Plugin();
3940
$plugin->setDeprecationHandler($service);
40-
$event = new Event('');
4141
$panel = new DeprecationsPanel();
4242

43-
//Without setting the $stackFrame
44-
deprecationWarning('setDeprecationHandler');
45-
//Setting the $stackFrame
46-
deprecationWarning('setDeprecationHandler_2', 2);
47-
//Raw error
48-
$line = __LINE__ + 1;
49-
trigger_error('raw_error', E_USER_DEPRECATED);
43+
$error = new PhpError(E_USER_WARNING, 'ignored', __FILE__, __LINE__, []);
44+
$event = new Event('Error.beforeRender', null, ['error' => $error]);
45+
EventManager::instance()->dispatch($event);
46+
47+
// No file/line in message.
48+
$error = new PhpError(E_USER_DEPRECATED, 'going away', __FILE__, __LINE__, []);
49+
$event = new Event('Error.beforeRender', null, ['error' => $error]);
50+
EventManager::instance()->dispatch($event);
51+
52+
// Formatted like deprecationWarning()
53+
$message = <<<TEXT
54+
Something deprecated happened.
55+
Don't use that thing.
56+
src/Plugin.php, line: 51
57+
You can disable all deprecation warnings by setting `Error.errorLevel` to `E_ALL & ~E_USER_DEPRECATED`.
58+
TEXT;
59+
$error = new PhpError(E_USER_DEPRECATED, $message, __FILE__, __LINE__, []);
60+
$event = new Event('Error.beforeRender', null, ['error' => $error]);
61+
EventManager::instance()->dispatch($event);
5062

5163
$panel->shutdown($event);
52-
$data = $panel->data()['plugins']['DebugKit'];
64+
$data = $panel->data();
65+
66+
$this->assertArrayHasKey('plugins', $data);
67+
$this->assertArrayHasKey('DebugKit', $data['plugins']);
68+
$this->assertCount(1, $data['plugins']['DebugKit']);
5369

54-
$this->assertCount(3, $data);
70+
$first = $data['plugins']['DebugKit'][0];
71+
$this->assertEquals($first['message'], 'going away');
72+
$this->assertEquals($first['file'], __FILE__);
73+
$this->assertEquals($first['line'], 48);
5574

56-
//test first two deprecationWarning()
57-
foreach ([$data[0], $data[1]] as $value) {
58-
$this->assertStringContainsString($value['file'], $value['message']);
59-
$this->assertStringContainsString("line: {$value['line']}", $value['message']);
60-
}
61-
//test raw error
62-
$this->assertSame($line, $data[2]['line']);
75+
$this->assertArrayHasKey('other', $data);
76+
$parsed = $data['other'][0];
77+
$this->assertEquals($parsed['message'], $message);
78+
$this->assertEquals($parsed['file'], 'src/Plugin.php');
79+
$this->assertEquals($parsed['line'], 51);
6380
}
6481
}

0 commit comments

Comments
 (0)