Administration/src/FuzeWorks/Administration/PageFinder.php

230 lines
8.2 KiB
PHP

<?php
/**
* FuzeWorks Framework Administration Plugin.
*
* The FuzeWorks PHP FrameWork
*
* Copyright (C) 2013-2020 i15
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @author i15
* @copyright Copyright (c) 2013 - 2020, i15. (https://i15.nl)
* @license https://opensource.org/licenses/MIT MIT License
*
* @since Version 1.3.0
*
* @version Version 1.3.0
*/
namespace FuzeWorks\Administration;
use FuzeWorks\Administration\Events\AdminGenerateSidebarEvent;
use FuzeWorks\Events;
use FuzeWorks\Factory;
use FuzeWorks\Logger;
use FuzeWorks\Priority;
use FuzeWorks\Views;
use phpDocumentor\Reflection\DocBlockFactory;
use ReflectionClass;
use ReflectionException;
use ReflectionMethod;
class PageFinder
{
/**
* Generates an array of all sidebar elements.
*
* First searches for all the available AdminViews. Then parses over all their methods and populates the array
* using each method's individual docblock.
*
* @return array
*/
public function generateSidebar(): array
{
Logger::log("Generating sidebar...");
$event = Events::fireEvent('adminGenerateSidebarEvent');
if ($event->isCancelled())
return [];
// First find all views
$viewFileList = $this->findViews();
Logger::log("Found " . count($viewFileList) . ' admin views.');
// Then sort all those views into methods in the sidebar
$sorted = $this->sort($viewFileList);
// Log the result and return
Logger::log("Found " . count($sorted) . ' entries for sidebar.');
return $sorted;
}
/**
* Parse over every view component path and find all admin views.
*
* Return a file list.
*
* @return array
*/
protected function findViews(): array
{
/** @var Views $views */
$views = Factory::getInstance('views');
// First collect all the known paths
$paths = [];
for ($i = Priority::getHighestPriority(); $i<=Priority::getLowestPriority(); $i++)
$paths[$i] = $views->getComponentPaths($i);
// Then go over every individual paths
$viewFiles = [];
foreach ($paths as $priority => $foldersArray)
{
foreach ($foldersArray as $folder)
{
// Get the contents from the folder
$contents = array_diff(scandir($folder), array('..', '.'));
// Then go over the folders, and see which ones are an admin view
foreach ($contents as $file)
{
// If the file matches the expected filename, add it to the list
if (substr($file, 0, 11) === 'view.admin.' && !isset($viewFiles[$file]))
$viewFiles[$file] = $folder . DS . $file;
}
}
}
return $viewFiles;
}
protected function sort(array $viewFileList): array
{
// Reflection docblock factory
$factory = DocBlockFactory::createInstance();
// Start sorting all methods
$entries = [];
foreach ($viewFileList as $viewId => $viewFile)
{
// Load the file
require_once $viewFile;
// Determine the className
$id = substr($viewId, 11, -4);
$className = 'Application\View\\' . ucfirst($id) . 'AdminView';
// Try and reflect on this class.
try {
$reflector = new ReflectionClass($className);
} catch (ReflectionException $e) {
// If that doesn't work, simply ignore it. Don't drag the whole interface down.
continue;
}
// Check if this class actually inherits AdminView
$parent = $reflector->getParentClass();
if ($parent === false || $parent->getName() !== 'FuzeWorks\Administration\AdminView')
continue;
// Select all methods
$methods = $reflector->getMethods(ReflectionMethod::IS_PUBLIC);
// And pass over all of them
foreach ($methods as $method) {
// Prepare the entry output
$entry = [
'url' => ($id !== 'index' ? $id : '') . ($method->getName() !== 'index' ? '/' . $method->getName() : ''),
'priority' => Priority::NORMAL,
'display' => $reflector->getShortName() . '/' . $method->getName(),
'icon' => 'round'
];
// Only allow the methods in the actual class. Not from the parent method.
if ($method->class !== $className)
continue;
// Then fetch the docComments.
$docComment = $method->getDocComment();
if ($docComment !== false)
{
$docBlock = $factory->create($docComment);
$docTags = $docBlock->getTags();
// Find known tags
$hidden = $docBlock->getTagsByName('hidden');
$display = $docBlock->getTagsByName('display');
$icon = $docBlock->getTagsByName('icon');
$priority = $docBlock->getTagsByName('priority');
// First test for hidden. If found, it should not be added to the sidebar
if (!empty($hidden))
continue;
// Then test for display
if (!empty($display))
$entry['display'] = (string) $display[0];
// Then test for icon
if (!empty($icon))
$entry['icon'] = (string) $icon[0];
// Then test for priority
if (!empty($priority))
{
$priority = (string) $priority[0];
switch ($priority) {
case 'Priority::LOWEST':
$entry['priority'] = 5;
break;
case 'Priority::LOW':
$entry['priority'] = 4;
break;
case 'Priority::NORMAL':
$entry['priority'] = 3;
break;
case 'Priority::HIGH':
$entry['priority'] = 2;
break;
case 'Priority::HIGHEST':
$entry['priority'] = 1;
break;
case 'Priority::MONITOR':
$entry['priority'] = 0;
break;
default:
Logger::logError("Method " . $reflector->getName() . '::' . $method->getName() . ' has invalid value for @priority.');
$entry['priority'] = 3;
break;
}
}
}
// Write to entries
$entries[] = $entry;
}
}
// And finally return those
return $entries;
}
}