Add tracy panel for DI container

[MAILPOET-2293]
This commit is contained in:
Pavel Dohnal
2019-08-29 15:24:56 +02:00
committed by Jack Kitterhing
parent e8253ad94e
commit 0e8a5bdb62
4 changed files with 204 additions and 0 deletions

View File

@ -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

View File

@ -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());

View 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>';
}
}
}

View 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>