Add tracy panel for DI container
[MAILPOET-2293]
This commit is contained in:
committed by
Jack Kitterhing
parent
e8253ad94e
commit
0e8a5bdb62
@ -5,6 +5,7 @@ use MailPoet\Config\AccessControl;
|
||||
use MailPoet\Settings\SettingsController;
|
||||
use MailPoet\Subscription\Captcha;
|
||||
use MailPoet\Tracy\ApiPanel\ApiPanel;
|
||||
use MailPoet\Tracy\DIPanel\DIPanel;
|
||||
use MailPoetVendor\Psr\Container\ContainerInterface;
|
||||
use MailPoet\Util\Helpers;
|
||||
use MailPoet\Util\Security;
|
||||
@ -169,6 +170,7 @@ class API {
|
||||
|
||||
if (class_exists(Debugger::class)) {
|
||||
ApiPanel::init($endpoint, $this->_request_method, $this->_request_data);
|
||||
DIPanel::init();
|
||||
}
|
||||
|
||||
// check the accessibility of the requested endpoint's action
|
||||
|
@ -6,7 +6,9 @@ use MailPoet\Config\Renderer;
|
||||
use MailPoet\Features\FeaturesController;
|
||||
use MailPoet\Referrals\ReferralDetector;
|
||||
use MailPoet\Settings\SettingsController;
|
||||
use MailPoet\Tracy\DIPanel\DIPanel;
|
||||
use MailPoet\WP\Notice as WPNotice;
|
||||
use Tracy\Debugger;
|
||||
|
||||
if (!defined('ABSPATH')) exit;
|
||||
|
||||
@ -41,6 +43,9 @@ class PageRenderer {
|
||||
'referral_id' => $this->settings->get(ReferralDetector::REFERRAL_SETTING_NAME),
|
||||
];
|
||||
try {
|
||||
if (class_exists(Debugger::class)) {
|
||||
DIPanel::init();
|
||||
}
|
||||
echo $this->renderer->render($template, $data + $defaults);
|
||||
} catch (\Exception $e) {
|
||||
$notice = new WPNotice(WPNotice::TYPE_ERROR, $e->getMessage());
|
||||
|
159
lib/Tracy/DIPanel/DIPanel.php
Normal file
159
lib/Tracy/DIPanel/DIPanel.php
Normal file
@ -0,0 +1,159 @@
|
||||
<?php
|
||||
|
||||
namespace MailPoet\Tracy\DIPanel;
|
||||
|
||||
use MailPoet\DI\ContainerWrapper;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\Reference;
|
||||
use MailPoetVendor\Symfony\Component\DependencyInjection\TypedReference;
|
||||
use Tracy\Debugger;
|
||||
use Tracy\IBarPanel;
|
||||
|
||||
class DIPanel implements IBarPanel {
|
||||
|
||||
/** @var string[] */
|
||||
private $free_services = [];
|
||||
|
||||
/** @var string[] */
|
||||
private $premium_services = [];
|
||||
|
||||
/** @var \MailPoetVendor\Symfony\Component\DependencyInjection\Definition[] */
|
||||
private $definitions = [];
|
||||
|
||||
/** @var string[][] */
|
||||
private $arguments_flattened = [];
|
||||
|
||||
function getTab() {
|
||||
$this->loadServices();
|
||||
$img = '<img
|
||||
src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAAeCAYAAAA7MK6iAAAAAXNSR0IArs4c6QAAAAlwSFlzAAAN1wAADdcBQiibeAAABCRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IlhNUCBDb3JlIDUuNC4wIj4KICAgPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICAgICAgPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIKICAgICAgICAgICAgeG1sbnM6dGlmZj0iaHR0cDovL25zLmFkb2JlLmNvbS90aWZmLzEuMC8iCiAgICAgICAgICAgIHhtbG5zOmV4aWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20vZXhpZi8xLjAvIgogICAgICAgICAgICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgICAgICAgICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyI+CiAgICAgICAgIDx0aWZmOlJlc29sdXRpb25Vbml0PjI8L3RpZmY6UmVzb2x1dGlvblVuaXQ+CiAgICAgICAgIDx0aWZmOkNvbXByZXNzaW9uPjA8L3RpZmY6Q29tcHJlc3Npb24+CiAgICAgICAgIDx0aWZmOlhSZXNvbHV0aW9uPjkwPC90aWZmOlhSZXNvbHV0aW9uPgogICAgICAgICA8dGlmZjpPcmllbnRhdGlvbj4xPC90aWZmOk9yaWVudGF0aW9uPgogICAgICAgICA8dGlmZjpZUmVzb2x1dGlvbj45MDwvdGlmZjpZUmVzb2x1dGlvbj4KICAgICAgICAgPGV4aWY6UGl4ZWxYRGltZW5zaW9uPjMwPC9leGlmOlBpeGVsWERpbWVuc2lvbj4KICAgICAgICAgPGV4aWY6Q29sb3JTcGFjZT4xPC9leGlmOkNvbG9yU3BhY2U+CiAgICAgICAgIDxleGlmOlBpeGVsWURpbWVuc2lvbj4zMDwvZXhpZjpQaXhlbFlEaW1lbnNpb24+CiAgICAgICAg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"
|
||||
style="height: 15px"
|
||||
/>';
|
||||
return $img . '<span class="tracy-label" >' . count($this->free_services) . ' + ' . count($this->premium_services) . ' services</span>';
|
||||
}
|
||||
|
||||
function getPanel() {
|
||||
ob_start();
|
||||
require __DIR__ . '/di-panel.phtml';
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
static function init() {
|
||||
Debugger::getBar()->addPanel(new static());
|
||||
}
|
||||
|
||||
private function loadServices() {
|
||||
list($services, $definitions) = $this->getServicesFromContainer('free_container');
|
||||
$this->free_services = array_keys($services);
|
||||
sort($this->free_services);
|
||||
$this->definitions = $definitions;
|
||||
$this->arguments_flattened = $this->flattenArguments($this->free_services);
|
||||
if (array_key_exists('premium_container', $services)) {
|
||||
list($services, $definitions) = $this->getServicesFromContainer('premium_container');
|
||||
$this->premium_services = array_keys($services);
|
||||
sort($this->premium_services);
|
||||
$this->definitions = array_merge($this->definitions, $definitions);
|
||||
$this->arguments_flattened = array_merge($this->flattenArguments($this->premium_services), $this->arguments_flattened);
|
||||
}
|
||||
}
|
||||
|
||||
private function getServicesFromContainer($name) {
|
||||
$container_wrapper = ContainerWrapper::getInstance();
|
||||
$reflection = new \ReflectionProperty(ContainerWrapper::class, $name);
|
||||
$reflection->setAccessible(true);
|
||||
$container = $reflection->getValue($container_wrapper);
|
||||
$reflection = new \ReflectionProperty(get_class($container), 'services');
|
||||
$reflection->setAccessible(true);
|
||||
return [$reflection->getValue($container), $container->getDefinitions()];
|
||||
}
|
||||
|
||||
/**
|
||||
* For each service finds all of its arguments recursively and makes them an array
|
||||
* @param string[] $services
|
||||
* @return array
|
||||
*/
|
||||
private function flattenArguments($services) {
|
||||
$result = [];
|
||||
foreach ($services as $service) {
|
||||
$result[$service] = [];
|
||||
$this->getAllArguments($service, $result[$service]);
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find all argument of each service and adds them to $results array, repeats recursively
|
||||
* @param string $service
|
||||
* @param string[] $results
|
||||
*/
|
||||
private function getAllArguments($service, &$results) {
|
||||
if (array_key_exists($service, $this->definitions)) {
|
||||
$arguments = $this->definitions[$service]->getArguments();
|
||||
if (!empty($arguments)) {
|
||||
foreach ($arguments as $argument) {
|
||||
if (is_null($argument)) continue;
|
||||
if ($argument instanceof TypedReference) {
|
||||
$argumentName = $argument->getType();
|
||||
} elseif ($argument instanceof Reference) {
|
||||
$argumentName = (string)$argument;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
$results[$argumentName] = $argumentName;
|
||||
if ($argumentName !== 'MailPoet\DI\ContainerWrapper') {
|
||||
$this->getAllArguments($argumentName, $results);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $item
|
||||
*/
|
||||
public function printItem($item) {
|
||||
echo $item;
|
||||
if (array_key_exists($item, $this->definitions)) {
|
||||
$arguments = $this->definitions[$item]->getArguments();
|
||||
if (!empty($arguments)) {
|
||||
echo '<span class="tracy-toggle tracy-collapsed">...</span>';
|
||||
echo '<div class="tracy-collapsed" style="padding-left: 10px">';
|
||||
foreach ($arguments as $argument) {
|
||||
if (is_null($argument)) {
|
||||
echo 'NULL <br>';
|
||||
} elseif ($argument instanceof TypedReference) {
|
||||
$this->printItem($argument->getType());
|
||||
echo '<br>';
|
||||
} elseif ($argument instanceof Reference) {
|
||||
$this->printItem((string)$argument);
|
||||
echo '<br>';
|
||||
} elseif (is_string($argument)) {
|
||||
echo $argument;
|
||||
echo '<br>';
|
||||
}
|
||||
}
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $item
|
||||
*/
|
||||
public function printUsages($item) {
|
||||
$used_in = [];
|
||||
foreach ($this->arguments_flattened as $service => $arguments) {
|
||||
if (array_key_exists($item, $arguments)) {
|
||||
$used_in[] = $service;
|
||||
}
|
||||
}
|
||||
|
||||
if (count($used_in)) {
|
||||
$label = 'Used in ' . count($used_in) . ' services';
|
||||
echo '<span class="tracy-toggle tracy-collapsed">' . $label . '...</span>';
|
||||
echo '<div class="tracy-collapsed" style="padding-left: 10px">';
|
||||
echo join('<br>', $used_in);
|
||||
echo '</div>';
|
||||
}
|
||||
}
|
||||
|
||||
}
|
38
lib/Tracy/DIPanel/di-panel.phtml
Normal file
38
lib/Tracy/DIPanel/di-panel.phtml
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace MailPoet\Tracy\DIPanel;
|
||||
|
||||
/**
|
||||
* @var DIPanel $this
|
||||
*/
|
||||
|
||||
?>
|
||||
<h1>Dependency Injection</h1>
|
||||
<div class="tracy-inner">
|
||||
<h2>Free (<?= count($this->free_services) ?> services)</h2>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Service</th>
|
||||
<th>Used In</th>
|
||||
</tr>
|
||||
<?php foreach ($this->free_services as $item): ?>
|
||||
<tr>
|
||||
<td><?php $this->printItem($item) ?></td>
|
||||
<td><?php $this->printUsages($item) ?></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</table>
|
||||
<h2>Premium (<?= count($this->premium_services) ?> services)</h2>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Service</th>
|
||||
<th>Used In</th>
|
||||
</tr>
|
||||
<?php foreach ($this->premium_services as $item): ?>
|
||||
<tr>
|
||||
<td><?php $this->printItem($item) ?></td>
|
||||
<td><?php $this->printUsages($item) ?></td>
|
||||
</tr>
|
||||
<?php endforeach ?>
|
||||
</table>
|
||||
</div>
|
Reference in New Issue
Block a user