286 lines
10 KiB
PHP
Executable File
286 lines
10 KiB
PHP
Executable File
<?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\Attributes\DisplayAttribute;
|
|
use FuzeWorks\Administration\Attributes\HiddenAttribute;
|
|
use FuzeWorks\Administration\Attributes\IconAttribute;
|
|
use FuzeWorks\Administration\Attributes\PermissionAttribute;
|
|
use FuzeWorks\Administration\Attributes\PriorityAttribute;
|
|
use FuzeWorks\Administration\Events\AdminFindViewsEvent;
|
|
use FuzeWorks\Administration\Events\AdminGenerateSidebarEvent;
|
|
use FuzeWorks\Authentication\Model\Session;
|
|
use FuzeWorks\Events;
|
|
use FuzeWorks\Factory;
|
|
use FuzeWorks\Logger;
|
|
use FuzeWorks\Priority;
|
|
use FuzeWorks\Views;
|
|
use ReflectionClass;
|
|
use ReflectionException;
|
|
use ReflectionMethod;
|
|
|
|
class PageFinder
|
|
{
|
|
|
|
|
|
protected Session $session;
|
|
|
|
/**
|
|
* 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 attributes.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function generateSidebar(Session $session): array
|
|
{
|
|
$this->session = $session;
|
|
|
|
Logger::log("Generating sidebar...");
|
|
$event = Events::fireEvent('adminGenerateSidebarEvent');
|
|
if ($event->isCancelled())
|
|
return [];
|
|
|
|
// First find all views
|
|
$views = $this->findViews();
|
|
Logger::log("Found " . count($views) . ' admin views.');
|
|
|
|
// Then sort all those views into methods in the sidebar
|
|
$sorted = $this->sortSidebar($views);
|
|
|
|
// Log the result and return
|
|
Logger::log("Found " . count($sorted) . ' entries for sidebar.');
|
|
return $sorted;
|
|
}
|
|
|
|
/**
|
|
* Find all views that have methods with attributes of a specific kind.
|
|
*
|
|
* @param string $attributeClass
|
|
* @return string[]
|
|
*/
|
|
public function findViewsWithAttribute(string $attributeClass): array
|
|
{
|
|
// First find all admin views
|
|
$views = $this->findViews();
|
|
return $this->sortByAttribute($views, $attributeClass);
|
|
}
|
|
|
|
/**
|
|
* Parse over every view component path and find all admin views.
|
|
*
|
|
* Return a file list.
|
|
*
|
|
* @return string[]
|
|
*/
|
|
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
|
|
$views = [];
|
|
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 (!str_starts_with($file, 'view.admin.'))
|
|
continue;
|
|
|
|
// Attempt to load the view
|
|
$viewFile = $folder . DS . $file;
|
|
$id = substr($file, 11, -4);
|
|
$className = 'Application\View\\' . ucfirst($id) . 'AdminView';
|
|
require_once($viewFile);
|
|
if (!class_exists($className))
|
|
continue;
|
|
|
|
$views[] = $className;
|
|
}
|
|
}
|
|
}
|
|
|
|
return $views;
|
|
}
|
|
|
|
/**
|
|
* Returns all views which have methods which have Attributes with the attributeClassName
|
|
*
|
|
* @param string[] $views
|
|
* @param string $attributeClassName
|
|
* @return string[]
|
|
*/
|
|
protected function sortByAttribute(array $views, string $attributeClassName): array
|
|
{
|
|
$out = [];
|
|
foreach ($views as $view)
|
|
{
|
|
try {
|
|
$reflector = new ReflectionClass($view);
|
|
} catch (ReflectionException $e) {
|
|
// If reflector doesn't work, simply ignore it.
|
|
continue;
|
|
}
|
|
|
|
// Check if the class actually inherits AdminView
|
|
if (!$reflector->isSubclassOf(AdminView::class))
|
|
continue;
|
|
|
|
// Select all methods
|
|
$methods = $reflector->getMethods(ReflectionMethod::IS_PUBLIC);
|
|
foreach ($methods as $method)
|
|
if (!empty($method->getAttributes($attributeClassName)))
|
|
$out[] = $view;
|
|
}
|
|
|
|
return $out;
|
|
}
|
|
|
|
protected function sortSidebar(array $views): array
|
|
{
|
|
// Start sorting all methods
|
|
$entries = [];
|
|
foreach ($views as $view)
|
|
{
|
|
// Try and reflect on this class.
|
|
try {
|
|
$reflector = new ReflectionClass($view);
|
|
} 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
|
|
if (!$reflector->isSubclassOf("FuzeWorks\Administration\AdminView"))
|
|
continue;
|
|
|
|
// Determine view Id
|
|
$id = strtolower(substr($reflector->getShortName(), 0, -9));
|
|
|
|
// 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 !== $view)
|
|
continue;
|
|
|
|
// Read attributes
|
|
// First read hidden attribute. If present, skip this method
|
|
$hiddenAttributes = $method->getAttributes(HiddenAttribute::class);
|
|
if (!empty($hiddenAttributes))
|
|
continue;
|
|
|
|
// Then check for permissions
|
|
$permissionAttributes = $method->getAttributes(PermissionAttribute::class);
|
|
if (!empty($permissionAttributes))
|
|
{
|
|
// Fetch nodes
|
|
$nodes = $permissionAttributes[0]->newInstance()->getValue();
|
|
|
|
// Check if any of the nodes are permitted
|
|
$found = false;
|
|
foreach ($nodes as $node)
|
|
if ($this->session->hasPermission($node))
|
|
$found = true;
|
|
|
|
// If not, skip
|
|
if (!$found)
|
|
continue;
|
|
}
|
|
|
|
// Then check for display attribute.
|
|
$displayAttributes = $method->getAttributes(DisplayAttribute::class);
|
|
if (!empty($displayAttributes))
|
|
$entry['display'] = $displayAttributes[0]->newInstance()->getValue();
|
|
|
|
// Then check for icon
|
|
$iconAttributes = $method->getAttributes(IconAttribute::class);
|
|
if (!empty($iconAttributes))
|
|
$entry['icon'] = $iconAttributes[0]->newInstance()->getValue();
|
|
|
|
// Then check for priority
|
|
$priorityAttributes = $method->getAttributes(PriorityAttribute::class);
|
|
if (!empty($priorityAttributes))
|
|
$entry['priority'] = $priorityAttributes[0]->newInstance()->getValue();
|
|
|
|
// Add priority
|
|
if (!isset($entries[$entry['priority']]))
|
|
$entries[$entry['priority']] = [];
|
|
|
|
// Write to entries
|
|
$entries[$entry['priority']][] = $entry;
|
|
}
|
|
}
|
|
|
|
// Sort by priority
|
|
$out = [];
|
|
for ($i = Priority::getHighestPriority(); $i <= Priority::getLowestPriority(); $i++) {
|
|
if (!isset($entries[$i]))
|
|
continue;
|
|
|
|
$p = $entries[$i];
|
|
foreach ($p as $entry)
|
|
$out[] = $entry;
|
|
}
|
|
|
|
// And finally return the sidebar entries
|
|
return $out;
|
|
}
|
|
|
|
} |