Skip to content

Commit

Permalink
Navigation panel
Browse files Browse the repository at this point in the history
  • Loading branch information
mabar committed Jul 8, 2018
1 parent 58de9b3 commit cdbc3c9
Show file tree
Hide file tree
Showing 10 changed files with 336 additions and 4 deletions.
20 changes: 18 additions & 2 deletions .docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## Content

- [TracyBlueScreensExtension - better BlueScreen panels](#tracybluescreensextension)
- [NavigationPanelExtension - navigate easily through all presenters](#navigationpanelextension)

## TracyBlueScreensExtension

Expand All @@ -13,8 +14,23 @@ extensions:
tracy.bluescreens: Contributte\Tracy\DI\TracyBlueScreensExtension
```
![Container Builder - parameters][container-builder-parameters]
![Container Builder - definitions][container-builder-definitions]
![Container Builder - parameters][container-builder-parameters]
![Container Builder - definitions][container-builder-definitions]
[container-builder-parameters]: https://raw.githubusercontent.com/contributte/tracy/master/.docs/assets/container-builder-parameters.png "Container Builder - parameters"
[container-builder-definitions]: https://raw.githubusercontent.com/contributte/tracy/master/.docs/assets/container-builder-definitions.png "Container Builder - definitions"
## NavigationPanelExtension
`NavigationPanelExtension` adds a Tracy bar panel for navigation across all presenters.

```yaml
extensions:
tracy.navigation: Contributte\Tracy\DI\NavigationTracyPanel
```

Links are generated for presenters which:

- Are registered into DIC (should be all of them, if application is not misconfigured)
- Inherits from Nette\Application\UI\Presenter
- Have at least one action or render method without parameters (or with optional parameters only)
Binary file added .docs/assets/navigation-panel.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ composer require contributte/tracy
## Overview

- [TracyBlueScreensExtension - better BlueScreen panels](https://github.com/contributte/tracy/blob/master/.docs/README.md#tracybluescreensextension)
- [NavigationPanelExtension - navigate easily through all presenters](https://github.com/contributte/tracy/blob/master/.docs/README.md#navigationpanelextension)

## Maintainers

Expand Down
18 changes: 16 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"tracy",
"profile",
"bluescreen",
"navigation",
"develop"
],
"type": "library",
Expand All @@ -17,6 +18,10 @@
{
"name": "Milan Felix Šulc",
"homepage": "https://f3l1x.io"
},
{
"name": "Marek Bartoš",
"homepage": "https://marek-bartos.cz"
}
],
"require": {
Expand All @@ -26,17 +31,26 @@
"require-dev": {
"ninjify/qa": "^0.8.0",
"ninjify/nunjuck": "^0.2.0",
"nette/di": "~2.4.12"
"nette/application": "~2.4.13",
"nette/di": "~2.4.13",
"nette/http": "~2.4.9"
},
"conflict": {
"nette/di": "<2.4.12",
"nette/application": "<2.4.13",
"nette/di": "<2.4.13",
"nette/http": "<2.4.9",
"nette/utils": "<2.5.2"
},
"autoload": {
"psr-4": {
"Contributte\\Tracy\\": "src"
}
},
"autoload-dev": {
"psr-4": {
"Tests\\Fixtures\\": "tests/fixtures"
}
},
"scripts": {
"qa": [
"linter src tests",
Expand Down
43 changes: 43 additions & 0 deletions src/DI/NavigationPanelExtension.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<?php declare(strict_types = 1);

namespace Contributte\Tracy\DI;

use Contributte\Tracy\NavigationPanel;
use Nette\Application\IPresenterFactory;
use Nette\Application\LinkGenerator;
use Nette\Application\UI\Presenter;
use Nette\DI\CompilerExtension;
use Nette\DI\Statement;

class NavigationPanelExtension extends CompilerExtension
{

/** @var mixed[] */
private $defaults = [];

public function loadConfiguration(): void
{
$this->validateConfig($this->defaults);
}

public function beforeCompile(): void
{
$builder = $this->getContainerBuilder();

$linkGenerator = '@' . $builder->getByType(LinkGenerator::class);
$presenterFactory = '@' . $builder->getByType(IPresenterFactory::class);
$presenters = $builder->findByType(Presenter::class);

foreach ($presenters as $key => $presenter) {
$presenters[$key] = $presenter->getType();
}

$builder
->getDefinition('tracy.bar')
->addSetup('addPanel', [
new Statement(NavigationPanel::class, [$presenterFactory, $linkGenerator, $presenters]),
$this->prefix('navigation'),
]);
}

}
118 changes: 118 additions & 0 deletions src/NavigationPanel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
<?php declare(strict_types = 1);

namespace Contributte\Tracy;

use Nette\Application\LinkGenerator;
use Nette\Application\PresenterFactory;
use Nette\Application\UI\InvalidLinkException;
use Nette\Utils\Strings;
use ReflectionClass;
use ReflectionMethod;
use Tracy\IBarPanel;

class NavigationPanel implements IBarPanel
{

/** @var PresenterFactory */
private $presenterFactory;

/** @var LinkGenerator */
private $linkGenerator;

/** @var string[] */
private $presenters;

/** @var mixed[] */
private $tree = [];

/**
* @param string[] $presenters
*/
public function __construct(
PresenterFactory $presenterFactory,
LinkGenerator $linkGenerator,
array $presenters
)
{
$this->presenterFactory = $presenterFactory;
$this->linkGenerator = $linkGenerator;
$this->presenters = $presenters;

$this->tree = $this->buildTree();
}

public function getTab(): string
{
ob_start();
require __DIR__ . '/Templates/NavigationPanel/tab.phtml';
return ob_get_clean();
}

public function getPanel(): string
{
$tree = $this->tree;
ob_start();
require __DIR__ . '/Templates/NavigationPanel/panel.phtml';
return ob_get_clean();
}

/**
* @return mixed[]
*/
private function buildTree(): array
{
$tree = [];

foreach ($this->presenters as $presenter) {
$rc = new ReflectionClass($presenter);
$methods = $rc->getMethods(ReflectionMethod::IS_PUBLIC);
$filteredMethods = [];

$presenter = $this->presenterFactory->unformatPresenterClass($presenter);

if ($presenter === null) {
continue;
}

$parts = explode(':', $presenter);
$presenter = array_pop($parts);
$module = implode(':', $parts);

foreach ($methods as $method) {
if (Strings::startsWith($method->name, 'action') || Strings::startsWith($method->name, 'render')) {
$filteredMethods[] = $method;
}
}

// Try create links to all available presenters
foreach ($filteredMethods as $method) {

$action = str_replace(['action', 'render'], '', $method->getName());
$action = lcfirst($action);

if (isset($tree[$module][$presenter][$action])) {
continue;
}

try {
$link = $this->linkGenerator->link($module ? sprintf('%s:%s:%s', $module, $presenter, $action) : sprintf('%s:%s', $presenter, $action));
$tree[$module][$presenter][$action] = $link;
} catch (InvalidLinkException $e) {
// Just trying generate link
}
}

if (!isset($tree[$module][$presenter]['default'])) {
try {
$link = $this->linkGenerator->link($module ? sprintf('%s:%s:', $module, $presenter) : sprintf('%s:', $presenter));
$tree[$module][$presenter]['default'] = $link;
} catch (InvalidLinkException $e) {
// Just trying generate link
}
}
}

return $tree;
}

}
71 changes: 71 additions & 0 deletions src/Templates/NavigationPanel/panel.phtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php declare(strict_types=1);

namespace Contributte\Tracy\Templates\NavigationPanel;

$getRowspan = function (array $array): int {
$size = 0;
foreach ($array as $content) {
if (is_array($content)) { //presenters
$size += count($content);
} else { //actions
$size++;
}
}
return $size;
}

?>
<h1>Navigation</h1>

<div class="tracy-inner">
<table style="width: 100%;">
<thead>
<tr>
<th>Module</th>
<th>Presenter</th>
<th>Action</th>
</tr>
</thead>
<tbody>
<?php $moduleRowspan = 1; ?>
<?php $presenterRowspan = 1; ?>
<?php foreach ($tree as $module => $presenters): ?>
<?php foreach ($presenters as $presenter => $actions): ?>
<?php foreach ($actions as $action => $url): ?>
<tr>

<?php if ($moduleRowspan === 1): ?>
<?php $moduleRowspan = $getRowspan($presenters) ?>
<td rowspan="<?php echo $moduleRowspan; ?>"><?php echo $module; ?></td>
<?php else: ?>
<?php $moduleRowspan = $moduleRowspan - 1; ?>
<?php endif; ?>


<?php if ($presenterRowspan === 1): ?>

<?php $presenterRowspan = $getRowspan($actions); ?>
<td rowspan="<?php echo $presenterRowspan ?>">
<a href="<?php echo $url; ?>">
<?php echo $presenter; ?>
</a>
</td>

<?php else: ?>
<?php $presenterRowspan = $presenterRowspan - 1; ?>
<?php endif; ?>


<td>
<a href="<?php echo $url; ?>">
<?php echo $action; ?>
</a>
</td>

</tr>
<?php endforeach; ?>
<?php endforeach; ?>
<?php endforeach; ?>
</tbody>
</table>
</div>
11 changes: 11 additions & 0 deletions src/Templates/NavigationPanel/tab.phtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php declare(strict_types = 1);

namespace Contributte\Tracy\Templates\NavigationPanel;

?>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 74.43 99.14">
<path
d="M21.92 99.14v-3.29a4.34 4.34 0 0 1 4.41-4.42h2.52c1.45 0 2-.53 2-2V41.1l10.79-.53v48.72c0 1.72.44 2.16 2.17 2.17h2.42a4.35 4.35 0 0 1 4.31 4.32v3.39zM37.21 0l1 .39a5 5 0 0 1 3.38 4.33c.18 2.56 0 5.13 0 7.79l-10.75.56V5.71A5.36 5.36 0 0 1 35.12.16a2.34 2.34 0 0 0 .35-.16zm37.22 24.8l-4.63 6.77-1.15 1.67c-1.43 2.08-1.43 2.07-4 2.2l-35.18 1.8-26.49 1.33h-.64l7.14-10.4-8.2-9.6 6.26-.36 25-1.32 27.65-1.42c1.74-.09 3.48-.22 5.22-.28a1.43 1.43 0 0 1 1 .3c2.71 3.08 5.33 6.18 8.02 9.31z"/>
<path
d="M45.61 71.72V51.57l27.53 1.48c-.67.81-1.2 1.44-1.74 2.07-1.95 2.28-3.88 4.58-5.87 6.82a1 1 0 0 0-.06 1.55c2.19 3.11 4.33 6.25 6.64 9.6zM0 59.27c2.68-3.14 5.32-6.23 8-9.3a.93.93 0 0 1 .65-.3q9 .45 18.06.95c.06 0 .11.06.2.11v20c-2.21-.1-4.35-.19-6.5-.31-4.15-.22-8.3-.45-12.45-.7a1.52 1.52 0 0 1-1-.48C4.58 65.96 2.33 62.66 0 59.27z"/>
</svg>
39 changes: 39 additions & 0 deletions tests/cases/DI/NavigationPanelExtension.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php declare(strict_types = 1);

/**
* Test: DI\NavigationPanelExtension
*/

use Contributte\Tracy\DI\NavigationPanelExtension;
use Contributte\Tracy\NavigationPanel;
use Nette\Bridges\ApplicationDI\ApplicationExtension;
use Nette\Bridges\HttpDI\HttpExtension;
use Nette\DI\Compiler;
use Nette\DI\Container;
use Nette\DI\ContainerLoader;
use Tester\Assert;
use Tests\Fixtures\RouterFactory;
use Tracy\Bar;
use Tracy\Bridges\Nette\TracyExtension;

require_once __DIR__ . '/../../bootstrap.php';

test(function (): void {
$loader = new ContainerLoader(TEMP_DIR, true);
$class = $loader->load(function (Compiler $compiler): void {
$compiler->addExtension('application', new ApplicationExtension());
$compiler->addExtension('http', new HttpExtension());
$compiler->addExtension('tracy', new TracyExtension());
$compiler->addExtension('tracy.navigation', new NavigationPanelExtension());
$compiler->addConfig(
[
'services' => [RouterFactory::class . '::createRouter'],
]
);
}, time());

/** @var Container $container */
$container = new $class();

Assert::type(NavigationPanel::class, $container->getByType(Bar::class)->getPanel('tracy.navigation.navigation'));
});
19 changes: 19 additions & 0 deletions tests/fixtures/RouterFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php declare(strict_types = 1);

namespace Tests\Fixtures;

use Nette\Application\IRouter;
use Nette\Application\Routers\Route;
use Nette\Application\Routers\RouteList;

class RouterFactory
{

public static function createRouter(): IRouter
{
$router = new RouteList();
$router[] = new Route('<presenter>/<action>[/<id>]', 'Homepage:default');
return $router;
}

}

0 comments on commit cdbc3c9

Please sign in to comment.