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; } }