Initial commit

This commit is contained in:
Abel Hoogeveen 2020-08-02 11:08:21 +02:00
commit 50608c18e7
Signed by: abelhooge
GPG Key ID: 387E8DC1F73306FC
18 changed files with 1291 additions and 0 deletions

4
.gitattributes vendored Normal file
View File

@ -0,0 +1,4 @@
.gitattributes export-ignore
.gitignore export-ignore
.drone.yml export-ignore
test/ export-ignore

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
composer.lock
composer.phar
.idea/
build/
test/temp/
vendor/

16
Dockerfile Normal file
View File

@ -0,0 +1,16 @@
FROM php:7.3-apache
MAINTAINER i15 <abel@i15.nl>
# Install PHP Deps
# First PDO and MySQL
RUN docker-php-ext-install mysqli pdo_mysql opcache
# Write application to image
ENV APACHE_DOCUMENT_ROOT /usr/src/admin/www
RUN sed -ri -e 's!/var/www/html!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/sites-available/*.conf
RUN sed -ri -e 's!/var/www/!${APACHE_DOCUMENT_ROOT}!g' /etc/apache2/apache2.conf /etc/apache2/conf-available/*.conf
RUN a2enmod rewrite
# Amend permissions
COPY --chown=www-data . /usr/src/admin
RUN chmod -R 777 /usr/src/admin/test/temp

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
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.

32
composer.json Normal file
View File

@ -0,0 +1,32 @@
{
"name": "fuzeworks/administration",
"description": "description",
"minimum-stability": "stable",
"license": ["MIT"],
"authors": [
{
"name": "Abel Hoogeveen",
"email": "abel@i15.nl"
}
],
"require": {
"php": ">=7.2.0",
"fuzeworks/core": "~1.2",
"fuzeworks/mvcr": "~1.2",
"fuzeworks/webcomponent": "~1.2",
"fuzeworks/layout": "~1.2",
"fuzeworks/database": "~1.2",
"latte/latte": "^2",
"almasaeed2010/adminlte": "^3",
"phpdocumentor/reflection-docblock": "^5"
},
"require-dev": {
"phpunit/phpunit": "^9",
"fuzeworks/tracycomponent": "~1.2"
},
"autoload": {
"psr-4": {
"FuzeWorks\\Administration\\": "src/FuzeWorks/Administration/"
}
}
}

38
config.admin.php Normal file
View File

@ -0,0 +1,38 @@
<?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
*/
return [
'admin_enabled' => true,
'admin_url' => 'admin'
];

View File

@ -0,0 +1,42 @@
<?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 Application\Controller;
use FuzeWorks\WebController;
class IndexController extends WebController
{
}

View File

@ -0,0 +1,80 @@
<?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 Application\Controller;
use FuzeWorks\Core;
use FuzeWorks\Priority;
use FuzeWorks\WebController;
class SettingsController extends WebController
{
public function findSettingsFiles(): array
{
// First collect all the known paths
$paths = [];
for ($i = Priority::getHighestPriority(); $i<=Priority::getLowestPriority(); $i++)
$paths[$i] = $this->config->getComponentPaths($i);
// And add the CorePath
$paths[Priority::getLowestPriority()][] = Core::$coreDir . DS . 'Config';
// Then go over every individual paths
$configFiles = [];
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, 7) === 'config.' && !isset($configFiles[$file]))
$configFiles[$file] = ['folder' => $folder, 'priority' => substr(Priority::getPriority($priority), 10)];
}
}
}
// At the end, sort the files
ksort($configFiles);
// And return them
return $configFiles;
}
}

View File

@ -0,0 +1,40 @@
<div class="row">
<div class="col-xl-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">Configuration Files</h3>
</div>
<!-- /.card-header -->
<div class="card-body p-0">
<table class="table table-striped">
<thead>
<tr>
<th style="width: 10px">#</th>
<th>Name</th>
<th>Folder</th>
<th>Priority</th>
<th style="width: 20px">View</th>
<th style="width: 20px">Edit</th>
</tr>
</thead>
<tbody>
{foreach $files as $fileName => $data}
<tr>
<td>{$iterator->getCounter()}</td>
<td>{$fileName}</td>
<td>{$data['folder']}</td>
<td>{$data['priority']}</td>
<td><button type="button" class="btn btn-block btn-success">VIEW</button></td>
<td><button type="button" class="btn btn-block btn-primary">EDIT</button></td>
</tr>
{/foreach}
</tbody>
</table>
</div>
<!-- /.card-body -->
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,268 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>AdminLTE 3 | Dashboard</title>
<!-- Tell the browser to be responsive to screen width -->
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Font Awesome -->
<link rel="stylesheet" href="/{$adminKey}/plugins/fontawesome-free/css/all.min.css">
<!-- Ionicons -->
<link rel="stylesheet" href="https://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
<!-- Tempusdominus Bbootstrap 4 -->
<link rel="stylesheet" href="/{$adminKey}/plugins/tempusdominus-bootstrap-4/css/tempusdominus-bootstrap-4.min.css">
<!-- iCheck -->
<link rel="stylesheet" href="/{$adminKey}/plugins/icheck-bootstrap/icheck-bootstrap.min.css">
<!-- JQVMap -->
<link rel="stylesheet" href="/{$adminKey}/plugins/jqvmap/jqvmap.min.css">
<!-- Theme style -->
<link rel="stylesheet" href="/{$adminKey}/dist/css/adminlte.min.css">
<!-- overlayScrollbars -->
<link rel="stylesheet" href="/{$adminKey}/plugins/overlayScrollbars/css/OverlayScrollbars.min.css">
<!-- Daterange picker -->
<link rel="stylesheet" href="/{$adminKey}/plugins/daterangepicker/daterangepicker.css">
<!-- summernote -->
<link rel="stylesheet" href="/{$adminKey}/plugins/summernote/summernote-bs4.css">
<!-- Google Font: Source Sans Pro -->
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,400i,700" rel="stylesheet">
</head>
<body class="hold-transition sidebar-mini layout-fixed">
<div class="wrapper">
<!-- Navbar -->
<nav class="main-header navbar navbar-expand navbar-white navbar-light">
<!-- Left navbar links -->
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link" data-widget="pushmenu" href="#" role="button"><i class="fas fa-bars"></i></a>
</li>
<li class="nav-item d-none d-sm-inline-block">
<a href="/" class="nav-link">Home</a>
</li>
</ul>
<!-- SEARCH FORM -->
<form class="form-inline ml-3">
<div class="input-group input-group-sm">
<input class="form-control form-control-navbar" type="search" placeholder="Search" aria-label="Search">
<div class="input-group-append">
<button class="btn btn-navbar" type="submit">
<i class="fas fa-search"></i>
</button>
</div>
</div>
</form>
<!-- Right navbar links -->
<ul class="navbar-nav ml-auto">
<!-- Messages Dropdown Menu -->
<li class="nav-item dropdown">
<a class="nav-link" data-toggle="dropdown" href="#">
<i class="far fa-comments"></i>
<span class="badge badge-danger navbar-badge">3</span>
</a>
<div class="dropdown-menu dropdown-menu-lg dropdown-menu-right">
<a href="#" class="dropdown-item">
<!-- Message Start -->
<div class="media">
<img src="/{$adminKey}/dist/img/user1-128x128.jpg" alt="User Avatar" class="img-size-50 mr-3 img-circle">
<div class="media-body">
<h3 class="dropdown-item-title">
Brad Diesel
<span class="float-right text-sm text-danger"><i class="fas fa-star"></i></span>
</h3>
<p class="text-sm">Call me whenever you can...</p>
<p class="text-sm text-muted"><i class="far fa-clock mr-1"></i> 4 Hours Ago</p>
</div>
</div>
<!-- Message End -->
</a>
<div class="dropdown-divider"></div>
<a href="#" class="dropdown-item">
<!-- Message Start -->
<div class="media">
<img src="/{$adminKey}/dist/img/user8-128x128.jpg" alt="User Avatar" class="img-size-50 img-circle mr-3">
<div class="media-body">
<h3 class="dropdown-item-title">
John Pierce
<span class="float-right text-sm text-muted"><i class="fas fa-star"></i></span>
</h3>
<p class="text-sm">I got your message bro</p>
<p class="text-sm text-muted"><i class="far fa-clock mr-1"></i> 4 Hours Ago</p>
</div>
</div>
<!-- Message End -->
</a>
<div class="dropdown-divider"></div>
<a href="#" class="dropdown-item">
<!-- Message Start -->
<div class="media">
<img src="/{$adminKey}/dist/img/user3-128x128.jpg" alt="User Avatar" class="img-size-50 img-circle mr-3">
<div class="media-body">
<h3 class="dropdown-item-title">
Nora Silvester
<span class="float-right text-sm text-warning"><i class="fas fa-star"></i></span>
</h3>
<p class="text-sm">The subject goes here</p>
<p class="text-sm text-muted"><i class="far fa-clock mr-1"></i> 4 Hours Ago</p>
</div>
</div>
<!-- Message End -->
</a>
<div class="dropdown-divider"></div>
<a href="#" class="dropdown-item dropdown-footer">See All Messages</a>
</div>
</li>
<!-- Notifications Dropdown Menu -->
<li class="nav-item dropdown">
<a class="nav-link" data-toggle="dropdown" href="#">
<i class="far fa-bell"></i>
<span class="badge badge-warning navbar-badge">15</span>
</a>
<div class="dropdown-menu dropdown-menu-lg dropdown-menu-right">
<span class="dropdown-item dropdown-header">15 Notifications</span>
<div class="dropdown-divider"></div>
<a href="#" class="dropdown-item">
<i class="fas fa-envelope mr-2"></i> 4 new messages
<span class="float-right text-muted text-sm">3 mins</span>
</a>
<div class="dropdown-divider"></div>
<a href="#" class="dropdown-item">
<i class="fas fa-users mr-2"></i> 8 friend requests
<span class="float-right text-muted text-sm">12 hours</span>
</a>
<div class="dropdown-divider"></div>
<a href="#" class="dropdown-item">
<i class="fas fa-file mr-2"></i> 3 new reports
<span class="float-right text-muted text-sm">2 days</span>
</a>
<div class="dropdown-divider"></div>
<a href="#" class="dropdown-item dropdown-footer">See All Notifications</a>
</div>
</li>
<li class="nav-item">
<a class="nav-link" data-widget="control-sidebar" data-slide="true" href="#" role="button">
<i class="fas fa-th-large"></i>
</a>
</li>
</ul>
</nav>
<!-- /.navbar -->
<!-- Main Sidebar Container -->
<aside class="main-sidebar sidebar-dark-primary elevation-4">
<!-- Brand Logo -->
<a href="index3.html" class="brand-link">
<img src="/{$adminKey}/dist/img/AdminLTELogo.png" alt="AdminLTE Logo" class="brand-image img-circle elevation-3"
style="opacity: .8">
<span class="brand-text font-weight-light">AdminLTE 3</span>
</a>
<!-- Sidebar -->
<div class="sidebar">
<!-- Sidebar user panel (optional) -->
<div class="user-panel mt-3 pb-3 mb-3 d-flex">
<div class="image">
<img src="/{$adminKey}/dist/img/user2-160x160.jpg" class="img-circle elevation-2" alt="User Image">
</div>
<div class="info">
<a href="#" class="d-block">Juris LLM</a>
</div>
</div>
<!-- Sidebar Menu -->
<nav class="mt-2">
<ul class="nav nav-pills nav-sidebar flex-column" data-widget="treeview" role="menu" data-accordion="false">
{foreach $sidebar as $item}
<li class="nav-item">
<a href="/{$adminKey}/{$item['url']}" class="nav-link">
<i class="nav-icon fas fa-{$item['icon']}"></i>
<p>{$item['display']}</p>
</a>
</li>
{/foreach}
</ul>
</nav>
<!-- /.sidebar-menu -->
</div>
<!-- /.sidebar -->
</aside>
<!-- Content Wrapper. Contains page content -->
<div class="content-wrapper">
<!-- Content Header (Page header) -->
<div class="content-header">
<div class="container-fluid">
<div class="row mb-2">
<div class="col-sm-6">
<h1 class="m-0 text-dark">Dashboard</h1>
</div><!-- /.col -->
<div class="col-sm-6">
<ol class="breadcrumb float-sm-right">
<li class="breadcrumb-item"><a href="#">Home</a></li>
<li class="breadcrumb-item active">Dashboard v1</li>
</ol>
</div><!-- /.col -->
</div><!-- /.row -->
</div><!-- /.container-fluid -->
</div>
<!-- /.content-header -->
<!-- Main content -->
<section class="content">
<div class="container-fluid">
{$content|noescape}
</div><!-- /.container-fluid -->
</section>
<!-- /.content -->
</div>
<!-- /.content-wrapper -->
<footer class="main-footer">
<strong>Copyright &copy; 2013-2020 <a href="https://i15.nl">i15.nl</a>.</strong>
All rights reserved.
<div class="float-right d-none d-sm-inline-block">
<b>Version</b> 1.3.0
</div>
</footer>
<!-- Control Sidebar -->
<aside class="control-sidebar control-sidebar-dark">
<!-- Control sidebar content goes here -->
</aside>
<!-- /.control-sidebar -->
</div>
<!-- ./wrapper -->
<!-- jQuery -->
<script src="/{$adminKey}/plugins/jquery/jquery.min.js"></script>
<!-- jQuery UI 1.11.4 -->
<script src="/{$adminKey}/plugins/jquery-ui/jquery-ui.min.js"></script>
<!-- Resolve conflict in jQuery UI tooltip with Bootstrap tooltip -->
<script>
$.widget.bridge('uibutton', $.ui.button)
</script>
<!-- Bootstrap 4 -->
<script src="/{$adminKey}/plugins/bootstrap/js/bootstrap.bundle.min.js"></script>
<!-- ChartJS -->
<script src="/{$adminKey}/plugins/chart.js/Chart.min.js"></script>
<!-- Sparkline -->
<script src="/{$adminKey}/plugins/sparklines/sparkline.js"></script>
<!-- JQVMap -->
<script src="/{$adminKey}/plugins/jqvmap/jquery.vmap.min.js"></script>
<script src="/{$adminKey}/plugins/jqvmap/maps/jquery.vmap.usa.js"></script>
<!-- jQuery Knob Chart -->
<script src="/{$adminKey}/plugins/jquery-knob/jquery.knob.min.js"></script>
<!-- daterangepicker -->
<script src="/{$adminKey}/plugins/moment/moment.min.js"></script>
<script src="/{$adminKey}/plugins/daterangepicker/daterangepicker.js"></script>
<!-- Tempusdominus Bootstrap 4 -->
<script src="/{$adminKey}/plugins/tempusdominus-bootstrap-4/js/tempusdominus-bootstrap-4.min.js"></script>
<!-- Summernote -->
<script src="/{$adminKey}/plugins/summernote/summernote-bs4.min.js"></script>
<!-- overlayScrollbars -->
<script src="/{$adminKey}/plugins/overlayScrollbars/js/jquery.overlayScrollbars.min.js"></script>
<!-- AdminLTE App -->
<script src="/{$adminKey}/dist/js/adminlte.js"></script>
</body>
</html>

View File

@ -0,0 +1,212 @@
<?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\Config;
use FuzeWorks\ConfigORM\ConfigORM;
use FuzeWorks\Controllers;
use FuzeWorks\Event\LayoutLoadEvent;
use FuzeWorks\Event\RouteWebRequestEvent;
use FuzeWorks\Events;
use FuzeWorks\Factory;
use FuzeWorks\Layout;
use FuzeWorks\Logger;
use FuzeWorks\Models;
use FuzeWorks\Priority;
use FuzeWorks\Resources;
use FuzeWorks\Router;
use FuzeWorks\Views;
class AdminPlugin implements \FuzeWorks\iPluginHeader
{
private $pluginKey = 'admin';
/** @var Config */
private $config;
/** @var Router */
private $router;
/** @var Models */
private $models;
/** @var Views */
private $views;
/** @var Controllers */
private $controllers;
/** @var ConfigORM */
private $adminCFG;
/**
* @var string
*/
private $pluginPath;
/**
* @inheritDoc
*/
public function init()
{
// Make a listener for a web request
Events::addListener([$this, 'routeWebRequestEventListener'], 'routeWebRequestEvent', Priority::NORMAL);
$this->pluginPath = dirname(__DIR__, 3);
}
public function routeWebRequestEventListener(RouteWebRequestEvent $event)
{
// If this request has nothing to do with the admin interface, don't bother routing the request
if (substr($event->uriString, 0, strlen($this->pluginKey)) !== $this->pluginKey)
return;
Logger::log("Administration: observed admin request. Activating plugin.");
// Load the dependencies
$this->config = Factory::getInstance('config');
$this->router = Factory::getInstance('router');
$this->models = Factory::getInstance('models');
$this->views = Factory::getInstance('views');
$this->controllers = Factory::getInstance('controllers');
// Load the admin configuration
$this->config->addComponentPath($this->pluginPath, Priority::LOWEST);
$this->adminCFG = $this->config->getConfig('admin');
// If admin is not enabled, stop here
if (!$this->adminCFG->get('admin_enabled'))
return;
// Now load the pluginKey
$this->pluginKey = $this->adminCFG->get('admin_url');
// If it does, register everything
/** @var Resources $resources */
$resources = Factory::getInstance('resources');
// Serve the AdminLTE distribution files
$adminLTE = $this->pluginPath . DS . 'vendor' . DS . 'almasaeed2010' . DS . 'adminlte';
$resources->registerResources('admin/dist', $adminLTE . DS . 'dist');
$resources->registerResources('admin/plugins', $adminLTE . DS . 'plugins');
// And serve the actual pages
$routeString = '^' . $this->pluginKey . '(|\/(?P<viewName>.*?)(|\/(?P<viewMethod>.*?)(|\/(?P<viewParameters>.*?))))';
$this->router->addRoute($routeString, ['callable' => [$this, 'adminCallable']], Priority::HIGHEST);
// And add componentPaths for models, views, controllers
$this->models->addComponentPath($this->pluginPath . DS . 'models', Priority::LOW);
$this->views->addComponentPath($this->pluginPath . DS . 'views', Priority::LOW);
$this->controllers->addComponentPath($this->pluginPath . DS . 'controllers', Priority::LOW);
}
public function adminCallable(array $matches, string $routeString)
{
Logger::log("AdminCallable called. Loading admin page.");
// Load layouts and assign componentPath, in case the loaded view needs access to it
/** @var Layout $layouts */
$layouts = Factory::getInstance('layouts');
$layouts->addComponentPath($this->pluginPath . DS . 'layouts', Priority::LOW);
// And add a layoutLoadEventListener, to add global administration variables
Events::addListener([$this, 'layoutLoadEventListener'], 'layoutLoadEvent', Priority::NORMAL);
// Let's generate the sidebar
$finder = new PageFinder();
$sidebar = $finder->generateSidebar();
// Afterwards, pass on to the admin view and its contents
Logger::log("Forwarding request to Router::defaultCallable().");
$matches['viewType'] = 'admin';
$content = $this->router->defaultCallable($matches, $routeString);
// Reset and assign
Logger::log("Generating panel wrapper.");
$layouts->reset(false);
$layouts->assign('sidebar', $sidebar);
$layouts->assign('content', $content);
// And load the page
Logger::log("Forwarding output back to Router.");
$page = $layouts->get('main/panel');
return $page;
}
/**
* Listener for LayoutLoadEvent
*
* Assigns variables to Layout that this plugin's layouts may require.
*
* @param LayoutLoadEvent $event
*/
public function layoutLoadEventListener(LayoutLoadEvent $event)
{
$event->assign('adminKey', $this->pluginKey);
}
/**
* @inheritDoc
*/
public function getName(): string
{
return 'FuzeWorksAdministration';
}
/**
* @inheritDoc
*/
public function getClassesPrefix(): ?string
{
return null;
}
/**
* @inheritDoc
*/
public function getSourceDirectory(): ?string
{
return null;
}
/**
* @inheritDoc
*/
public function getPluginClass(): ?string
{
return null;
}
}

View File

@ -0,0 +1,61 @@
<?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\Factory;
use FuzeWorks\Layout;
use FuzeWorks\Priority;
use FuzeWorks\WebView;
abstract class AdminView extends WebView
{
/** @var Layout */
protected $layouts;
/**
* The priority of this AdminView.
*
* @var int
*/
protected $priority = Priority::NORMAL;
public function __construct()
{
parent::__construct();
$this->layouts = Factory::getInstance('layouts');
}
}

View File

@ -0,0 +1,230 @@
<?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;
}
}

63
test/bootstrap.php Normal file
View File

@ -0,0 +1,63 @@
<?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
*/
require_once(dirname(__DIR__) . '/vendor/autoload.php');
$configurator = new \FuzeWorks\Configurator();
// Set directories
$configurator->setTempDirectory(__DIR__ . '/temp');
$configurator->setLogDirectory(__DIR__ . '/temp');
// Other values
$configurator->setTimeZone('Europe/Amsterdam');
// Add components and plugins
$webComponent = new \FuzeWorks\WebComponent();
$webComponent->enableComponent();
$configurator->addComponent($webComponent);
// Add LayoutComponent
$configurator->addComponent(new \FuzeWorks\LayoutComponent());
// Add TracyComponent
$configurator->addComponent(new \FuzeWorks\TracyComponent());
// Debug related
$configurator->enableDebugMode();
$configurator->setDebugAddress('ALL');
$container = $configurator->createContainer();
$container->plugins->addPlugin(new \FuzeWorks\Administration\AdminPlugin());
return $container;

View File

@ -0,0 +1,55 @@
<?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 Application\View;
use FuzeWorks\Administration\AdminView;
class IndexAdminView extends AdminView
{
/**
* Hello!
*
* This does a lot of things
*
* @display Dashboard
* @icon tachometer-alt
* @priority Priority::HIGHEST
*/
public function index()
{
}
}

View File

@ -0,0 +1,78 @@
<?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 Application\View;
use Application\Controller\SettingsController;
use FuzeWorks\Administration\AdminView;
class SettingsAdminView extends AdminView
{
/**
* @var SettingsController
*/
protected $controller;
/**
* Displays a list of settings files
*
* @display Settings
* @icon cog
* @priority Priority::LOW
*/
public function index()
{
$files = $this->controller->findSettingsFiles();
$this->layouts->assign('files', $files);
return $this->layouts->get('components/settings/overview');
}
/**
* @hidden
*/
public function view()
{
}
/**
* @hidden
*/
public function modify()
{
}
}

4
www/.htaccess Normal file
View File

@ -0,0 +1,4 @@
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule (.*) index.php?path=$1 [QSA,L]

41
www/index.php Normal file
View File

@ -0,0 +1,41 @@
<?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
*/
/** @var \FuzeWorks\Factory $container */
$container = require(dirname(__DIR__) . '/test/bootstrap.php');
/** @var \FuzeWorks\WebComponent $web */
$web = $container->web;
$web->routeWebRequest();