Skip to content

Instantly share code, notes, and snippets.

@Skrip42
Created October 10, 2019 06:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Skrip42/8dc165829e59b5dbd3bfed1685679164 to your computer and use it in GitHub Desktop.
Save Skrip42/8dc165829e59b5dbd3bfed1685679164 to your computer and use it in GitHub Desktop.
<?php
namespace App\Services;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use WhiteOctober\BreadcrumbsBundle\Model\Breadcrumbs;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Security;
use ReflectionClass;
use Doctrine\Common\Annotations\AnnotationReader;
use Doctrine\Common\Annotations\CachedReader;
use Doctrine\Common\Cache\PhpFileCache;
use Symfony\Component\HttpKernel\KernelInterface;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\IsGranted;
class PageMap
{
/** @var array $map */ private $map;
/** @var Breadcrumbs $breadcrumbs */
private $breadcrumbs;
/** @var Security $security */
private $security;
/** @var string $currentRoute*/
private $currentRoute;
/** @var UrlGeneratorInterface $urlGenerator */
private $urlGenerator;
/** @var RouterInterface $router */
private $router;
/** @var KernelInterface $kernel*/
private $kernel;
/** @var string $currentNodeName */
private $currentNodeName = 'home';
/** @var array $currentNode */
private $currentNode;
/** @var array $paths */
private $paths = [];
/** @var array $routeList */
private $routeList;
/** @var array $routeMapDictinary */
private $routeMapDictinary;
public function __construct(
Breadcrumbs $breadcrumbs,
RequestStack $request,
ContainerInterface $container,
UrlGeneratorInterface $urlGenerator,
RouterInterface $router,
Security $security,
KernelInterface $kernel
) {
$this->router = $router;
$this->breadcrumbs = $breadcrumbs;
$this->urlGenerator = $urlGenerator;
$this->security = $security;
$this->kernel = $kernel;
$this->map = $container->getParameter('pagemap');
if (!empty($request->getCurrentRequest())) {
$this->currentRoute = $request->getCurrentRequest()->get('_route');
}
$this->generateFlat($this->map['home']);
$this->prepareAnnotation();
$this->prepareMap($this->map['home']);
$this->paths = $this->generatePath($this->map['home'], ['home']);
$this->generateBreadCrumbs();
dump($this->map);
}
/**
* Collect controllers annotation
*
* add is granted to node
*/
private function prepareAnnotation()
{
$reader = new CachedReader(
new AnnotationReader(),
new PhpFileCache($this->kernel->getProjectDir() . '/var/cache/phpmap/'),
true
);
foreach ($this->router->getRouteCollection() as $routeName => $route) {
if (empty($this->routeMapDictinary[$routeName])) {
continue;
}
list($classname, $methodname) = explode('::', $route->getDefaults()['_controller']);
$reflectionClass = new ReflectionClass($classname);
$classIsGranted = $reader->getClassAnnotation($reflectionClass, IsGranted::class);
$reflectionMethod = $reflectionClass->getMethod($methodname);
$methodIsGranted = $reader->getMethodAnnotation($reflectionMethod, IsGranted::class);
$granted = $methodIsGranted ?? $classIsGranted;
$this->routeMapDictinary[$routeName]['granted'] = !empty($granted) ? $granted->getAttributes() : false;
}
}
/**
* Create flat node dictinaris
*
* @param array &$node
*
* @return null
*/
private function generateFlat(array &$node)
{
if ($node['route']) {
$this->routeMapDictinary[$node['route']] = &$node;
}
if (!empty($node['childs'])) {
foreach ($node['childs'] as &$child) {
$this->generateFlat($child);
}
}
}
/**
* Recursive preparing map
*
* add url, expand property and fix nav property from granted
*
* @param array &$node
*
* @return bool is node expanded
*/
private function prepareMap(array &$node) : bool
{
if ($node['granted']) {
$node['nav'] = $node['nav'] && $this->security->isGranted($node['granted']);
}
if ($node['route'] && $node['nav']) {
$params = $node['default_param'] ?? [];
$node['url'] = $this->urlGenerator->generate(
$node['route'],
$params
);
}
$expand = false;
if (!empty($node['childs'])) {
foreach ($node['childs'] as &$child) {
$expand = $this->prepareMap($child) || $expand;
}
}
$node['expand'] = $expand;
return $node['nav'] || $expand;
}
/**
* Generate bread crumbs for current page
*
* @return null
*/
private function generateBreadCrumbs()
{
$path = $this->getPath();
$nodes = $this->map;
foreach ($path as $nodeName) {
$node = $nodes[$nodeName];
if (!empty($node['route']) && $node['route'] !== $this->currentRoute) {
$params = $node['default_param'] ?? [];
$this->breadcrumbs->addRouteItem(
$node['title'],
$node['route'],
$params
);
} else {
$this->breadcrumbs->addItem($node['title']);
}
if (empty($node['childs'])) {
break;
}
$nodes = $node['childs'];
}
}
/**
* Get title for curent page
*
* @return string
*/
public function getCurrentTitle() : string
{
return $this->currentNode['title'];
}
/**
* Return page map
*
* @return array
*/
public function getMap() : array
{
return $this->map;
}
/**
* Return route => node dictinary
*
* @return array
*/
public function getRouteDictinary() : array
{
return $this->routeMapDictinary;
}
/**
* Return path to current page
*
* @return array
*/
public function getPath() : array
{
return $this->paths[$this->currentNodeName];
}
/**
* Generate path dictinary
*
* @param array $node
* @param array $path
*
* @return array
*/
private function generatePath(array $node, array $path) : array
{
$nodeName = end($path);
if (!empty($node['route']) && $node['route'] == $this->currentRoute) {
$this->currentNodeName = $nodeName;
$this->currentNode = $node;
}
$flat = [];
$flat[$nodeName] = $path;
if (!empty($node['childs'])) {
foreach ($node['childs'] as $name => $child) {
foreach ($this->generatePath($child, array_merge($path, [$name])) as $eln => $el) {
$flat[$eln] = $el;
};
}
}
return $flat;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment