<?php
namespace PHPFUI\InstaDoc;
class Controller
{
public const CLASS_NAME = 'c';
public const CSS_FILE = 'CSS';
public const DOC_PAGE = 'd';
public const FILE_PAGE = 'f';
public const GIT_LIMIT = 'gl';
public const GIT_ONPAGE = 'gp';
public const GIT_PAGE = 'g';
public const GIT_SHA1 = 'gs';
public const NAMESPACE = 'n';
public const PAGE = 'p';
public const TAB_SIZE = 't';
public const VALID_CLASS_PAGES = [
Controller::DOC_PAGE,
Controller::FILE_PAGE,
Controller::GIT_PAGE,
];
private const SECTIONS = [
'Git',
'File',
'Doc',
'Landing',
'Home',
'GitDiff',
];
private const VALID_PARAMETERS = [
Controller::NAMESPACE => '',
Controller::CLASS_NAME => '',
Controller::TAB_SIZE => '',
Controller::CSS_FILE => '',
Controller::PAGE => '',
Controller::GIT_LIMIT => '',
Controller::GIT_ONPAGE => '',
Controller::GIT_SHA1 => '',
];
private const VALID_STATIC_PARTS = [
Controller::NAMESPACE,
Controller::CLASS_NAME,
Controller::PAGE,
];
private array $accessTabs = ['Public', 'Protected', 'Private', 'Static'];
private string $generating = '';
private string $gitFileOffset = '';
private string $gitRoot = '';
private array $homePageMarkdown = [];
private string $homeUrl = '#';
private ?\PHPFUI\Menu $menu = null;
private \PHPFUI\InstaDoc\PageInterface $page;
private array $parameters = [];
private string $siteTitle = 'PHPFUI/InstaDoc';
public function __construct(private \PHPFUI\InstaDoc\FileManager $fileManager)
{
$this->gitRoot = $fileManager->getComposerPath();
$this->page = $this->getPage();
$this->setParameters($this->page->getQueryParameters());
}
public function addHomePageMarkdown(string $path) : Controller
{
$this->homePageMarkdown[$path] = true;
return $this;
}
public function clearMenu() : Controller
{
$this->menu = null;
return $this;
}
public function display(array $classPagesToShow = Controller::VALID_CLASS_PAGES, ?PageInterface $page = null) : string
{
if (! $page)
{
$page = $this->getControllerPage();
$page->setPageName($this->siteTitle);
$page->setHomeUrl($this->homeUrl);
}
$page->setGenerating($this->generating);
$page->create($this->getMenu());
$mainColumn = new \PHPFUI\Container();
if (! $this->getParameter(Controller::CLASS_NAME) && $this->getParameter(Controller::NAMESPACE))
{
$mainColumn->add($this->getSection('Landing')->generate($page, $this->getParameter(Controller::NAMESPACE)));
}
elseif ($this->getParameter(Controller::CLASS_NAME))
{
$nameSpace = $this->getParameter(Controller::NAMESPACE);
if ($nameSpace)
{
$nameSpace .= '\\';
}
$fullClassName = $nameSpace . $this->getParameter(Controller::CLASS_NAME);
$tree = NamespaceTree::findNamespace($this->getParameter(Controller::NAMESPACE));
$files = $tree->getClassFilenames();
$fullClassPath = $files[$fullClassName] ?? '';
if ($this->getParameter(Controller::GIT_SHA1))
{
return $this->getSection('GitDiff')->generate($page, $fullClassName);
}
$section = new Section($this);
$div = new \PHPFUI\GridX();
$div->add($section->getBreadCrumbs($fullClassName));
$div->add(' ');
$icon = new \PHPFUI\FAIcon('far', 'clipboard');
$icon->setToolTip('Send Constructor to Clipboard');
$div->add($icon);
$callout = new \PHPFUI\Callout('success');
$callout->add('Copied!');
$callout->addClass('small');
$parameters = $this->getConstructorParameters($fullClassName);
$parameters = \str_replace("\n", '', $parameters);
$page->addCopyToClipboard("new \\{$fullClassName}({$parameters});", $icon, $callout);
$div->add($callout);
$mainColumn->add($div);
$mainColumn->add($section->getMenu($fullClassName, $classPagesToShow));
if (Controller::DOC_PAGE == $this->getParameter(Controller::PAGE))
{
$mainColumn->add($this->getSection('Doc')->generate($page, $fullClassPath));
}
elseif (Controller::GIT_PAGE == $this->getParameter(Controller::PAGE))
{
$mainColumn->add($this->getSection('Git')->generate($page, $fullClassPath));
}
elseif (Controller::FILE_PAGE == $this->getParameter(Controller::PAGE))
{
$mainColumn->add($this->getSection('File')->generate($page, $fullClassPath));
}
else
{
$mainColumn->add($this->getSection('Doc')->generate($page, $fullClassPath));
}
}
else
{
$mainColumn->add($this->getSection('Home')->generate($page, ''));
}
$page->addBody($mainColumn);
return "{$page}";
}
public function generate(string $directoryPath, array $pagesToInclude = [Controller::DOC_PAGE], string $extension = '.html') : array
{
if (! \file_exists($directoryPath))
{
throw new \Exception("The directory {$directoryPath} does not exist");
}
$count = 1;
$start = \microtime(true);
$this->generating = $extension;
$directoryPath .= '/';
$directoryPath = \str_replace('//', '/', $directoryPath);
$page = $this->getPage();
$page->setPageName($this->siteTitle);
$page->setHomeUrl($this->homeUrl);
\file_put_contents($directoryPath . 'index' . $extension, $this->display($pagesToInclude, $page));
$namespaces = [];
foreach (NamespaceTree::getAllClasses() as $path => $class)
{
$parameters = $this->getClassParts($class);
$namespaces[$parameters[Controller::NAMESPACE]] = true;
foreach ($pagesToInclude as $page)
{
$parameters[Controller::PAGE] = $page;
$this->setParameters($parameters);
$page = $this->getPage();
$page->setPageName($this->siteTitle);
$page->setHomeUrl($this->homeUrl);
\file_put_contents($directoryPath . $this->getUrl($parameters), $this->display($pagesToInclude, $page));
++$count;
}
}
$parameters = [];
foreach ($namespaces as $namespace => $value)
{
$parameters[Controller::NAMESPACE] = $namespace;
$page = $this->getPage();
$page->setPageName($this->siteTitle);
$page->setHomeUrl($this->homeUrl);
\file_put_contents($directoryPath . $this->getUrl($parameters), $this->display($pagesToInclude, $page));
++$count;
}
$this->generating = '';
$milliseconds = \microtime(true) - $start;
return ['count' => $count, 'seconds' => $milliseconds];
}
public function getAccessTabs() : array
{
return $this->accessTabs;
}
public function getClassParts(string $namespacedClass) : array
{
$parts = \explode('\\', $namespacedClass);
$namespace = '';
$backSlash = '';
while (\count($parts) > 1)
{
$namespace .= $backSlash . \array_shift($parts);
$backSlash = '\\';
}
$class = $parts[0];
$parameters = [
Controller::NAMESPACE => $namespace,
Controller::CLASS_NAME => $class,
];
return $parameters;
}
public function getClassUrl(string $namespacedClass) : string
{
$url = $this->getUrl($this->getClassParts($namespacedClass) + $this->getParameters());
return $url;
}
public function getConstructorParameters(string $className) : string
{
try
{
$reflection = new \ReflectionClass($className);
}
catch (\Exception)
{
return '';
}
$methodName = '__construct';
if (! $reflection->hasMethod($methodName))
{
return '';
}
$method = $reflection->getMethod($methodName);
$section = new \PHPFUI\InstaDoc\Section\CodeCommon($this, $className);
$parameters = $section->getMethodParameters($method);
return \Soundasleep\Html2Text::convert($parameters, ['drop_links' => true, 'ignore_errors' => true]);
}
public function getControllerPage() : PageInterface
{
return $this->page;
}
public function getFileManager() : FileManager
{
return $this->fileManager;
}
public function getGitFileOffset() : string
{
return $this->gitFileOffset;
}
public function getGitRoot() : string
{
return $this->gitRoot;
}
public function getHomePageMarkdown() : array
{
return \array_keys($this->homePageMarkdown);
}
public function getLandingPageUrl(string $namespace) : string
{
$parameters = $this->getParameters();
$parameters[Controller::NAMESPACE] = $namespace;
unset($parameters[Controller::CLASS_NAME], $parameters[Controller::PAGE]);
$url = $this->getUrl($parameters);
return $url;
}
public function getMenu(?\PHPFUI\Menu $menu = null) : \PHPFUI\Menu
{
if (! $this->generating && $this->menu)
{
return $this->menu;
}
NamespaceTree::setActiveClass($this->getParameter(Controller::CLASS_NAME));
NamespaceTree::setActiveNamespace($this->getParameter(Controller::NAMESPACE));
NamespaceTree::setController($this);
if (! $menu)
{
$menu = new \PHPFUI\AccordionMenu();
}
$this->menu = $menu;
NamespaceTree::populateMenu($this->menu);
return $this->menu;
}
public function getNamespaceURL(string $namespace) : string
{
while (\strlen($namespace) && '\\' == $namespace[0])
{
$namespace = \substr($namespace, 1);
}
$url = $this->getUrl([Controller::PAGE => Controller::DOC_PAGE, Controller::NAMESPACE => $namespace] + $this->getParameters());
return $url;
}
public function getPage() : \PHPFUI\InstaDoc\PageInterface
{
$page = new Page($this);
return $page;
}
public function getPageURL(string $page) : string
{
$parameters = $this->getParameters();
if (! \in_array($page, Controller::VALID_CLASS_PAGES))
{
throw new \Exception("Page {$page} is not in " . \implode(', ', Controller::VALID_CLASS_PAGES));
}
$parameters[Controller::PAGE] = $page;
$url = $this->getUrl($parameters);
return $url;
}
public function getParameter(string $parameter, ?string $default = null) : string
{
if (! isset(Controller::VALID_PARAMETERS[$parameter]))
{
throw new \Exception($parameter . ' is an invalid parameter. Valid values: ' . \implode(',', Controller::VALID_PARAMETERS));
}
return $this->parameters[$parameter] ?? $default ?? '';
}
public function getParameters() : array
{
return $this->parameters;
}
public function getSection(string $sectionName) : Section
{
if (! \in_array($sectionName, Controller::SECTIONS))
{
throw new \Exception("{$sectionName} is not one of " . \implode(', ', Controller::SECTIONS));
}
$class = 'PHPFUI\\InstaDoc\\Section\\' . $sectionName;
return new $class($this);
}
public function getUrl(array $parameters) : string
{
foreach ($parameters as $key => $value)
{
if (! \strlen($value))
{
unset($parameters[$key]);
}
}
if (! $this->generating)
{
$url = $this->page->getBaseUrl() . '?' . \http_build_query($parameters);
return \str_replace('\\', '%5C', $url);
}
$parts = [];
foreach (Controller::VALID_STATIC_PARTS as $part)
{
if (isset($parameters[$part]))
{
$parts[] = \str_replace('\\', '_', $parameters[$part]);
}
}
$url = \implode('_', $parts) . $this->generating;
while ('_' == $url[0])
{
$url = \substr($url, 1);
}
return $url;
}
public function setAccessTabs(array $tabs) : Controller
{
$this->accessTabs = $tabs;
return $this;
}
public function setGitFileOffset(string $directory) : Controller
{
$this->gitFileOffset = $directory;
return $this;
}
public function setGitRoot(string $directory) : Controller
{
$this->gitRoot = $directory;
if (empty($this->getGitFileOffset()))
{
$this->setGitFileOffset($directory);
}
return $this;
}
public function setHomeUrl(string $url) : Controller
{
$this->homeUrl = $url;
$this->page->setHomeUrl($url);
return $this;
}
public function setPageTitle(string $title) : Controller
{
$this->siteTitle = $title;
return $this;
}
public function setParameter(string $parameter, string $value) : Controller
{
if (! isset(Controller::VALID_PARAMETERS[$parameter]))
{
throw new \Exception($parameter . ' is an invalid parameter. Valid values: ' . \implode(',', Controller::VALID_PARAMETERS));
}
$this->parameters[$parameter] = $value;
return $this;
}
public function setParameters(array $parameters) : Controller
{
$this->parameters = [];
foreach (Controller::VALID_PARAMETERS as $key => $value)
{
if (isset($parameters[$key]) && \strlen($parameters[$key]))
{
$this->parameters[$key] = $parameters[$key];
}
}
return $this;
}
}