2022-04-24 14:32:58 +02:00
|
|
|
<?php
|
|
|
|
namespace Grav\Plugin;
|
|
|
|
|
|
|
|
use Composer\Autoload\ClassLoader;
|
|
|
|
use Grav\Common\Debugger;
|
|
|
|
use Grav\Common\Grav;
|
|
|
|
use Grav\Common\Page\Interfaces\PageInterface;
|
|
|
|
use Grav\Common\Page\Pages;
|
|
|
|
use Grav\Common\Page\Types;
|
|
|
|
use Grav\Common\Plugin;
|
|
|
|
use Grav\Common\User\Interfaces\UserInterface;
|
|
|
|
use Grav\Common\Utils;
|
|
|
|
use Grav\Events\FlexRegisterEvent;
|
|
|
|
use Grav\Events\PermissionsRegisterEvent;
|
|
|
|
use Grav\Events\PluginsLoadedEvent;
|
|
|
|
use Grav\Framework\Acl\PermissionsReader;
|
|
|
|
use Grav\Framework\Flex\FlexDirectory;
|
|
|
|
use Grav\Framework\Flex\FlexForm;
|
|
|
|
use Grav\Framework\Flex\Interfaces\FlexAuthorizeInterface;
|
|
|
|
use Grav\Framework\Flex\Interfaces\FlexInterface;
|
|
|
|
use Grav\Framework\Form\Interfaces\FormInterface;
|
|
|
|
use Grav\Framework\Route\Route;
|
|
|
|
use Grav\Plugin\Admin\Admin;
|
|
|
|
use Grav\Plugin\FlexObjects\Controllers\ObjectController;
|
|
|
|
use Grav\Plugin\FlexObjects\FlexFormFactory;
|
|
|
|
use Grav\Plugin\Form\Forms;
|
|
|
|
use Grav\Plugin\FlexObjects\Admin\AdminController;
|
|
|
|
use Grav\Plugin\FlexObjects\Flex;
|
|
|
|
use Psr\Http\Message\ServerRequestInterface;
|
|
|
|
use RocketTheme\Toolbox\Event\Event;
|
|
|
|
use function is_array;
|
|
|
|
use function is_callable;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Class FlexObjectsPlugin
|
|
|
|
* @package Grav\Plugin
|
|
|
|
*/
|
|
|
|
class FlexObjectsPlugin extends Plugin
|
|
|
|
{
|
|
|
|
/** @var string */
|
|
|
|
protected const MIN_GRAV_VERSION = '1.7.0';
|
|
|
|
|
|
|
|
/** @var int[] */
|
|
|
|
public $features = [
|
|
|
|
'blueprints' => 1000,
|
|
|
|
];
|
|
|
|
|
|
|
|
/** @var AdminController */
|
|
|
|
protected $controller;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return bool
|
|
|
|
*/
|
|
|
|
public static function checkRequirements(): bool
|
|
|
|
{
|
|
|
|
return version_compare(GRAV_VERSION, static::MIN_GRAV_VERSION, '>=');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return array
|
|
|
|
*
|
|
|
|
* The getSubscribedEvents() gives the core a list of events
|
|
|
|
* that the plugin wants to listen to. The key of each
|
|
|
|
* array section is the event that the plugin listens to
|
|
|
|
* and the value (in the form of an array) contains the
|
|
|
|
* callable (or function) as well as the priority. The
|
|
|
|
* higher the number the higher the priority.
|
|
|
|
*/
|
|
|
|
public static function getSubscribedEvents(): array
|
|
|
|
{
|
|
|
|
if (!static::checkRequirements()) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
|
|
|
return [
|
|
|
|
PluginsLoadedEvent::class => [
|
|
|
|
['initializeFlex', 10]
|
|
|
|
],
|
|
|
|
PermissionsRegisterEvent::class => [
|
|
|
|
['onRegisterPermissions', 100]
|
|
|
|
],
|
|
|
|
FlexRegisterEvent::class => [
|
|
|
|
['onRegisterFlex', 100]
|
|
|
|
],
|
|
|
|
'onCliInitialize' => [
|
|
|
|
['autoload', 100000],
|
|
|
|
['initializeFlex', 10]
|
|
|
|
],
|
|
|
|
'onPluginsInitialized' => [
|
|
|
|
['onPluginsInitialized', 0],
|
|
|
|
],
|
|
|
|
'onFormRegisterTypes' => [
|
|
|
|
['onFormRegisterTypes', 0]
|
|
|
|
]
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get list of form field types specified in this plugin. Only special types needs to be listed.
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function getFormFieldTypes()
|
|
|
|
{
|
|
|
|
return [
|
|
|
|
'list' => [
|
|
|
|
'array' => true
|
|
|
|
],
|
|
|
|
'pagemedia' => [
|
|
|
|
'array' => true,
|
|
|
|
'media_field' => true,
|
|
|
|
'validate' => [
|
|
|
|
'type' => 'ignore'
|
|
|
|
]
|
|
|
|
],
|
|
|
|
'filepicker' => [
|
|
|
|
'media_picker_field' => true
|
|
|
|
],
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return ClassLoader
|
|
|
|
*/
|
|
|
|
public function autoload(): ClassLoader
|
|
|
|
{
|
|
|
|
return require __DIR__ . '/vendor/autoload.php';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* [PluginsLoadedEvent:10]: Initialize Flex
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function initializeFlex(): void
|
|
|
|
{
|
|
|
|
$config = $this->config->get('plugins.flex-objects.directories') ?? [];
|
|
|
|
|
|
|
|
// Add to DI container
|
|
|
|
$this->grav['flex_objects'] = static function (Grav $grav) use ($config) {
|
|
|
|
/** @var FlexInterface $flex */
|
|
|
|
$flex = $grav['flex'];
|
|
|
|
|
|
|
|
$flexObjects = new Flex($flex, $config);
|
|
|
|
|
|
|
|
// This event is for backwards compatibility only, do not use it!
|
|
|
|
$grav->fireEvent('onFlexInit', new Event(['flex' => $flexObjects]));
|
|
|
|
|
|
|
|
return $flexObjects;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initialize the plugin
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function onPluginsInitialized(): void
|
|
|
|
{
|
|
|
|
if ($this->isAdmin()) {
|
|
|
|
/** @var UserInterface|null $user */
|
|
|
|
$user = $this->grav['user'] ?? null;
|
|
|
|
|
|
|
|
if (null === $user || !$user->authorize('login', 'admin')) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->enable([
|
|
|
|
'onAdminTwigTemplatePaths' => [
|
|
|
|
['onAdminTwigTemplatePaths', 10]
|
|
|
|
],
|
|
|
|
'onAdminMenu' => [
|
|
|
|
['onAdminMenu', 0]
|
|
|
|
],
|
|
|
|
'onAdminPage' => [
|
|
|
|
['onAdminPage', 0]
|
|
|
|
],
|
|
|
|
'onAdminCompilePresetSCSS' => [
|
|
|
|
['onAdminCompilePresetSCSS', 0]
|
|
|
|
],
|
|
|
|
'onDataTypeExcludeFromDataManagerPluginHook' => [
|
|
|
|
['onDataTypeExcludeFromDataManagerPluginHook', 0]
|
|
|
|
],
|
|
|
|
'onAdminControllerInit' => [
|
|
|
|
['onAdminControllerInit', 0]
|
|
|
|
],
|
|
|
|
'onThemeInitialized' => [
|
|
|
|
['onThemeInitialized', 0]
|
|
|
|
],
|
|
|
|
'onPageInitialized' => [
|
|
|
|
['onAdminPageInitialized', 0]
|
|
|
|
],
|
|
|
|
'onTwigSiteVariables' => [
|
|
|
|
['onTwigAdminVariables', 0]
|
|
|
|
],
|
|
|
|
'onGetPageTemplates' =>
|
|
|
|
['onGetPageTemplates', 0]
|
|
|
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
$this->enable([
|
|
|
|
'onTwigTemplatePaths' => [
|
|
|
|
['onTwigTemplatePaths', 0]
|
|
|
|
],
|
|
|
|
'onPagesInitialized' => [
|
|
|
|
['onPagesInitialized', -10000]
|
|
|
|
],
|
|
|
|
'onPageInitialized' => [
|
|
|
|
['authorizePage', 10000]
|
|
|
|
],
|
|
|
|
'onBeforeFlexFormInitialize' => [
|
|
|
|
['onBeforeFlexFormInitialize', -10]
|
|
|
|
],
|
|
|
|
'onPageTask' => [
|
|
|
|
['onPageTask', -10]
|
|
|
|
],
|
|
|
|
]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param FlexRegisterEvent $event
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function onRegisterFlex(FlexRegisterEvent $event): void
|
|
|
|
{
|
|
|
|
/** @var \Grav\Framework\Flex\Flex $flex */
|
|
|
|
$flex = $event->flex;
|
|
|
|
$types = (array)$this->config->get('plugins.flex-objects.directories', []);
|
|
|
|
$this->registerDirectories($flex, $types);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function onThemeInitialized(): void
|
|
|
|
{
|
|
|
|
// Register directories defined in the theme.
|
|
|
|
/** @var \Grav\Framework\Flex\Flex $flex */
|
|
|
|
$flex = $this->grav['flex'];
|
|
|
|
$types = (array)$this->config->get('plugins.flex-objects.directories', []);
|
|
|
|
$this->registerDirectories($flex, $types, true);
|
|
|
|
|
|
|
|
$this->controller = new AdminController();
|
|
|
|
|
|
|
|
/** @var Debugger $debugger */
|
|
|
|
$debugger = Grav::instance()['debugger'];
|
|
|
|
$names = implode(', ', array_keys($flex->getDirectories()));
|
|
|
|
$debugger->addMessage(sprintf('Registered flex types: %s', $names), 'debug');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param Event $event
|
|
|
|
*/
|
|
|
|
public function onBeforeFlexFormInitialize(Event $event): void
|
|
|
|
{
|
|
|
|
/** @var array $form */
|
|
|
|
$form = $event['form'];
|
|
|
|
$edit = $form['actions']['edit'] ?? false;
|
|
|
|
if (!isset($form['flex']['key']) && $edit === true) {
|
|
|
|
/** @var Route $route */
|
|
|
|
$route = $this->grav['route'];
|
2022-12-16 11:23:50 +01:00
|
|
|
$id = rawurldecode($route->getGravParam('id'));
|
2022-04-24 14:32:58 +02:00
|
|
|
if (null !== $id) {
|
|
|
|
$form['flex']['key'] = $id;
|
|
|
|
$event['form'] = $form;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* [onPagesInitialized:-10000] Default router for flex pages.
|
|
|
|
*
|
|
|
|
* @param Event $event
|
|
|
|
*/
|
|
|
|
public function onPagesInitialized(Event $event): void
|
|
|
|
{
|
|
|
|
/** @var Route|null $route */
|
|
|
|
$route = $event['route'] ?? null;
|
|
|
|
if (null === $route) {
|
|
|
|
// Stop if in CLI.
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @var PageInterface|null $page */
|
|
|
|
$page = $this->grav['page'] ?? null;
|
|
|
|
|
|
|
|
$base = '';
|
|
|
|
$path = [];
|
|
|
|
if (!$page->routable() || $page->template() === 'notfound') {
|
|
|
|
/** @var Pages $pages */
|
|
|
|
$pages = $this->grav['pages'];
|
|
|
|
|
|
|
|
// Find first existing and routable parent page.
|
|
|
|
$parts = explode('/', $route->getRoute());
|
|
|
|
array_shift($parts);
|
|
|
|
$page = null;
|
|
|
|
while (!$page && $parts) {
|
|
|
|
$path[] = array_pop($parts);
|
|
|
|
$base = '/' . implode('/', $parts);
|
|
|
|
$page = $pages->find($base);
|
|
|
|
if ($page && !$page->routable()) {
|
|
|
|
$page = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If page is found, check if it contains flex directory router.
|
|
|
|
if ($page) {
|
|
|
|
$flex = $this->grav['flex'];
|
|
|
|
$options = $page->header()->flex ?? null;
|
|
|
|
$router = $options['router'] ?? null;
|
|
|
|
$type = $options['directory'] ?? null;
|
|
|
|
$directory = $type ? $flex->getDirectory($type) : null;
|
|
|
|
if (\is_string($router)) {
|
|
|
|
$path = implode('/', array_reverse($path));
|
|
|
|
$response = null;
|
|
|
|
$flexEvent = new Event([
|
|
|
|
'flex' => $flex,
|
|
|
|
'directory' => $directory,
|
|
|
|
'parent' => $page,
|
|
|
|
'page' => $page,
|
|
|
|
'base' => $base,
|
|
|
|
'path' => $path,
|
|
|
|
'route' => $route,
|
|
|
|
'options' => $options,
|
|
|
|
'request' => $event['request'],
|
|
|
|
'response' => &$response,
|
|
|
|
]);
|
|
|
|
$flexEvent = $this->grav->fireEvent("flex.router.{$router}", $flexEvent);
|
|
|
|
if ($response) {
|
|
|
|
$this->grav->close($response);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @var PageInterface|null $routedPage */
|
|
|
|
$routedPage = $flexEvent['page'];
|
|
|
|
if ($routedPage) {
|
|
|
|
/** @var Debugger $debugger */
|
|
|
|
$debugger = Grav::instance()['debugger'];
|
|
|
|
$debugger->addMessage(sprintf('Flex uses page %s', $routedPage->route()));
|
|
|
|
|
|
|
|
unset($this->grav['page']);
|
|
|
|
$this->grav['page'] = $routedPage;
|
|
|
|
$event->stopPropagation();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* [onPageInitialized:10000] Authorize Flex Objects Page
|
|
|
|
*
|
|
|
|
* @param Event $event
|
|
|
|
*/
|
|
|
|
public function authorizePage(Event $event): void
|
|
|
|
{
|
|
|
|
/** @var PageInterface|null $page */
|
|
|
|
$page = $event['page'];
|
|
|
|
if (!$page instanceof PageInterface) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$header = $page->header();
|
|
|
|
$forms = $page->getForms();
|
|
|
|
|
|
|
|
// Update dynamic flex forms from the page.
|
|
|
|
$form = null;
|
|
|
|
foreach ($forms as $name => $test) {
|
|
|
|
$type = $form['type'] ?? null;
|
|
|
|
if ($type === 'flex') {
|
|
|
|
$form = $test;
|
|
|
|
|
|
|
|
// Update the form and add it back to the page.
|
|
|
|
$this->grav->fireEvent('onBeforeFlexFormInitialize', new Event(['page' => $page, 'name' => $name, 'form' => &$form]));
|
|
|
|
$page->addForms([$form], true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make sure the page contains flex.
|
|
|
|
$config = $header->flex ?? null;
|
|
|
|
if (!is_array($config) && !$form) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @var Route $route */
|
|
|
|
$route = $this->grav['route'];
|
|
|
|
|
|
|
|
$type = $form['flex']['type'] ?? $config['directory'] ?? $route->getGravParam('directory') ?? null;
|
|
|
|
$key = $form['flex']['key'] ?? $config['id'] ?? $route->getGravParam('id') ?? '';
|
|
|
|
if (\is_string($type)) {
|
|
|
|
/** @var Flex $flex */
|
|
|
|
$flex = $this->grav['flex_objects'];
|
|
|
|
$directory = $flex->getDirectory($type);
|
|
|
|
} else {
|
|
|
|
$directory = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$directory) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$create = (bool)($form['actions']['create'] ?? false);
|
|
|
|
$edit = (bool)($form['actions']['edit'] ?? false);
|
|
|
|
|
|
|
|
$scope = $config['access']['scope'] ?? null;
|
|
|
|
|
|
|
|
$object = $key !== '' ? $directory->getObject($key) : null;
|
|
|
|
$hasAccess = null;
|
|
|
|
|
|
|
|
$action = $config['access']['action'] ?? null;
|
|
|
|
if (null === $action) {
|
|
|
|
if (!$form) {
|
|
|
|
$action = $key !== '' ? 'read' : 'list';
|
|
|
|
if (null === $scope) {
|
|
|
|
$hasAccess = true;
|
|
|
|
}
|
|
|
|
} elseif ($object) {
|
|
|
|
if ($edit) {
|
|
|
|
$scope = $scope ?? 'admin';
|
|
|
|
$action = 'update';
|
|
|
|
} else {
|
|
|
|
$hasAccess = false;
|
|
|
|
}
|
|
|
|
} elseif ($create) {
|
|
|
|
$object = $directory->createObject([], $key);
|
|
|
|
$scope = $scope ?? 'admin';
|
|
|
|
$action = 'create';
|
|
|
|
} else {
|
|
|
|
$hasAccess = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ($action && $hasAccess === null) {
|
|
|
|
if ($object instanceof FlexAuthorizeInterface) {
|
|
|
|
$hasAccess = $object->isAuthorized($action, $scope);
|
|
|
|
} else {
|
|
|
|
$hasAccess = $directory->isAuthorized($action, $scope);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$hasAccess) {
|
|
|
|
// Hide the page (404).
|
|
|
|
$page->routable(false);
|
|
|
|
$page->visible(false);
|
|
|
|
|
|
|
|
// If page is not a module, replace the current page with unauthorized page.
|
|
|
|
if (!$page->isModule()) {
|
|
|
|
$login = $this->grav['login'] ?? null;
|
|
|
|
$unauthorized = $login ? $login->addPage('unauthorized') : null;
|
|
|
|
if ($unauthorized) {
|
|
|
|
unset($this->grav['page']);
|
|
|
|
$this->grav['page'] = $unauthorized;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} elseif ($config['access']['override'] ?? false) {
|
|
|
|
// Override page access settings (allow).
|
|
|
|
$page->modifyHeader('access', []);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param Event $event
|
|
|
|
*/
|
|
|
|
public function onPageTask(Event $event): void
|
|
|
|
{
|
|
|
|
/** @var FormInterface|null $form */
|
|
|
|
$form = $event['form'] ?? null;
|
|
|
|
if (!$form instanceof FlexForm) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
$object = $form->getObject();
|
|
|
|
|
|
|
|
/** @var ServerRequestInterface $request */
|
|
|
|
$request = $event['request'];
|
|
|
|
$request = $request
|
|
|
|
->withAttribute('type', $object->getFlexType())
|
|
|
|
->withAttribute('key', $object->getKey())
|
|
|
|
->withAttribute('object', $object)
|
|
|
|
->withAttribute('form', $form);
|
|
|
|
|
|
|
|
$controller = new ObjectController();
|
|
|
|
|
|
|
|
$response = $controller->handle($request);
|
|
|
|
if ($response->getStatusCode() !== 418) {
|
|
|
|
$this->grav->close($response);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param \Grav\Framework\Flex\Flex $flex
|
|
|
|
* @param array $types
|
|
|
|
* @param bool $report
|
|
|
|
*/
|
|
|
|
protected function registerDirectories(\Grav\Framework\Flex\Flex $flex, array $types, bool $report = false): void
|
|
|
|
{
|
|
|
|
$map = Flex::getLegacyBlueprintMap(false);
|
|
|
|
foreach ($types as $blueprint) {
|
|
|
|
// Backwards compatibility to v1.0.0-rc.3
|
|
|
|
$blueprint = $map[$blueprint] ?? $blueprint;
|
|
|
|
$type = Utils::basename((string)$blueprint, '.yaml');
|
|
|
|
if (!$type) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!file_exists($blueprint)) {
|
|
|
|
if ($report) {
|
|
|
|
/** @var Debugger $debugger */
|
|
|
|
$debugger = Grav::instance()['debugger'];
|
|
|
|
$debugger->addMessage(sprintf('Flex: blueprint for flex type %s is missing', $type), 'error');
|
|
|
|
}
|
|
|
|
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$directory = $flex->getDirectory($type);
|
|
|
|
if (!$directory || !$directory->isEnabled()) {
|
|
|
|
$flex->addDirectoryType($type, $blueprint);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Initial stab at registering permissions (WIP)
|
|
|
|
*
|
|
|
|
* @param PermissionsRegisterEvent $event
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function onRegisterPermissions(PermissionsRegisterEvent $event): void
|
|
|
|
{
|
|
|
|
/** @var Flex $flex */
|
|
|
|
$flex = $this->grav['flex_objects'];
|
|
|
|
$directories = $flex->getDirectories();
|
|
|
|
|
|
|
|
$permissions = $event->permissions;
|
|
|
|
|
|
|
|
$actions = [];
|
|
|
|
foreach ($directories as $directory) {
|
|
|
|
$data = $directory->getConfig('admin.permissions', []);
|
|
|
|
$actions[] = PermissionsReader::fromArray($data, $permissions->getTypes());
|
|
|
|
|
|
|
|
}
|
|
|
|
$actions[] = PermissionsReader::fromYaml("plugin://{$this->name}/permissions.yaml");
|
|
|
|
|
|
|
|
$permissions->addActions(array_replace(...$actions));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param Event $event
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function onFormRegisterTypes(Event $event): void
|
|
|
|
{
|
|
|
|
/** @var Forms $forms */
|
|
|
|
$forms = $event['forms'];
|
|
|
|
$forms->registerType('flex', new FlexFormFactory());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param Event $event
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function onAdminPage(Event $event): void
|
|
|
|
{
|
|
|
|
if ($this->controller->isActive()) {
|
|
|
|
$event->stopPropagation();
|
|
|
|
|
|
|
|
/** @var PageInterface $page */
|
|
|
|
$page = $event['page'];
|
|
|
|
$page->init(new \SplFileInfo(__DIR__ . '/admin/pages/flex-objects.md'));
|
|
|
|
$page->slug($this->controller->getLocation());
|
|
|
|
$header = $page->header();
|
|
|
|
$header->access = ['admin.login'];
|
|
|
|
$header->controller = $this->controller->getInfo();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* [onPageInitialized:0]: Run controller
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function onAdminPageInitialized(): void
|
|
|
|
{
|
|
|
|
if ($this->controller->isActive()) {
|
|
|
|
$this->controller->execute();
|
|
|
|
$this->controller->redirect();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param Event $event
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function onAdminControllerInit(Event $event): void
|
|
|
|
{
|
|
|
|
$eventController = $event['controller'];
|
|
|
|
|
|
|
|
// Blacklist all admin routes, including aliases and redirects.
|
|
|
|
$eventController->blacklist_views[] = 'flex-objects';
|
|
|
|
foreach ($this->controller->getAdminRoutes() as $route => $info) {
|
|
|
|
$eventController->blacklist_views[] = trim($route, '/');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add Flex-Object's preset.scss to the Admin Preset SCSS compile process
|
|
|
|
*
|
|
|
|
* @param Event $event
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function onAdminCompilePresetSCSS(Event $event): void
|
|
|
|
{
|
|
|
|
$event['scss']->add($this->grav['locator']->findResource('plugins://flex-objects/scss/_preset.scss'));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @param Event $event
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function onGetPageTemplates(Event $event): void
|
|
|
|
{
|
|
|
|
/** @var Types $types */
|
|
|
|
$types = $event->types;
|
|
|
|
$types->register('flex-objects', 'plugins://flex-objects/blueprints/pages/flex-objects.yaml');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Form select options listing all enabled directories.
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public static function directoryOptions(): array
|
|
|
|
{
|
|
|
|
/** @var Flex $flex */
|
|
|
|
$flex = Grav::instance()['flex_objects'];
|
|
|
|
$directories = $flex->getDirectories();
|
|
|
|
|
|
|
|
$list = [];
|
|
|
|
/**
|
|
|
|
* @var string $type
|
|
|
|
* @var FlexDirectory $directory
|
|
|
|
*/
|
|
|
|
foreach ($directories as $type => $directory) {
|
|
|
|
if (!$directory->getConfig('site.hidden')) {
|
|
|
|
$list[$type] = $directory->getTitle();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return $list;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function getAdminMenu(): array
|
|
|
|
{
|
|
|
|
/** @var Flex $flex */
|
|
|
|
$flex = $this->grav['flex_objects'];
|
|
|
|
|
|
|
|
$list = [];
|
|
|
|
foreach ($flex->getAdminMenuItems() as $name => $item) {
|
|
|
|
$route = trim($item['route'] ?? $name, '/');
|
|
|
|
$list[$route] = $item;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $list;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add Flex Directory to admin menu
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function onAdminMenu(): void
|
|
|
|
{
|
|
|
|
/** @var Flex $flex */
|
|
|
|
$flex = $this->grav['flex_objects'];
|
|
|
|
/** @var Admin $admin */
|
|
|
|
$admin = $this->grav['admin'];
|
|
|
|
|
|
|
|
foreach ($this->getAdminMenu() as $route => $item) {
|
|
|
|
$directory = null;
|
|
|
|
if (isset($item['directory'])) {
|
|
|
|
$directory = $flex->getDirectory($item['directory']);
|
|
|
|
if (!$directory || !$directory->isEnabled()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
$title = $item['title'] ?? 'PLUGIN_FLEX_OBJECTS.TITLE';
|
|
|
|
$index = $item['index'] ?? 0;
|
|
|
|
if (($this->grav['twig']->plugins_hooked_nav[$title]['index'] ?? 1000) <= $index) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
$location = $item['location'] ?? $route;
|
|
|
|
$hidden = $item['hidden'] ?? false;
|
|
|
|
$icon = $item['icon'] ?? 'fa-list';
|
|
|
|
$authorize = $item['authorize'] ?? ($directory ? null : ['admin.flex-objects', 'admin.super']);
|
|
|
|
if ($hidden || (null === $authorize && $directory->isAuthorized('list', 'admin', $admin->user))) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
$cache = $directory ? $directory->getCache('index') : null;
|
|
|
|
$count = $cache ? $cache->get('admin-count-' . md5($admin->user->username)) : false;
|
|
|
|
if (null === $count) {
|
|
|
|
try {
|
|
|
|
$collection = $directory->getCollection();
|
|
|
|
if (is_callable([$collection, 'isAuthorized'])) {
|
|
|
|
$count = $collection->isAuthorized('list', 'admin', $admin->user)->count();
|
|
|
|
} else {
|
|
|
|
$count = $collection->count();
|
|
|
|
}
|
|
|
|
$cache->set('admin-count-' . md5($admin->user->username), $count);
|
|
|
|
} catch (\InvalidArgumentException $e) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
$badge = $directory ? ['badge' => ['count' => $count]] : [];
|
|
|
|
$priority = $item['priority'] ?? 0;
|
|
|
|
|
|
|
|
$this->grav['twig']->plugins_hooked_nav[$title] = [
|
|
|
|
'location' => $location,
|
|
|
|
'route' => $route,
|
|
|
|
'index' => $index,
|
|
|
|
'icon' => $icon,
|
|
|
|
'authorize' => $authorize,
|
|
|
|
'priority' => $priority
|
|
|
|
] + $badge;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Exclude Flex Directory data from the Data Manager plugin
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function onDataTypeExcludeFromDataManagerPluginHook(): void
|
|
|
|
{
|
|
|
|
$this->grav['admin']->dataTypesExcludedFromDataManagerPlugin[] = 'flex-objects';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add current directory to twig lookup paths.
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function onTwigTemplatePaths(): void
|
|
|
|
{
|
|
|
|
$extra_site_twig_path = $this->config->get('plugins.flex-objects.extra_site_twig_path');
|
|
|
|
$extra_path = $extra_site_twig_path ? $this->grav['locator']->findResource($extra_site_twig_path) : null;
|
|
|
|
if ($extra_path) {
|
|
|
|
$this->grav['twig']->twig_paths[] = $extra_path;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->grav['twig']->twig_paths[] = __DIR__ . '/templates';
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Add plugin templates path
|
|
|
|
*
|
|
|
|
* @param Event $event
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function onAdminTwigTemplatePaths(Event $event): void
|
|
|
|
{
|
|
|
|
$extra_admin_twig_path = $this->config->get('plugins.flex-objects.extra_admin_twig_path');
|
|
|
|
$extra_path = $extra_admin_twig_path ? $this->grav['locator']->findResource($extra_admin_twig_path) : null;
|
|
|
|
|
|
|
|
$paths = $event['paths'];
|
|
|
|
if ($extra_path) {
|
|
|
|
$paths[] = $extra_path;
|
|
|
|
}
|
|
|
|
|
|
|
|
$paths[] = __DIR__ . '/admin/templates';
|
|
|
|
$event['paths'] = $paths;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Set needed variables to display directory.
|
|
|
|
*
|
|
|
|
* @return void
|
|
|
|
*/
|
|
|
|
public function onTwigAdminVariables(): void
|
|
|
|
{
|
|
|
|
if ($this->controller->isActive()) {
|
|
|
|
// Twig shortcuts
|
|
|
|
$this->grav['twig']->twig_vars['controller'] = $this->controller;
|
|
|
|
$this->grav['twig']->twig_vars['action'] = $this->controller->getAction();
|
|
|
|
$this->grav['twig']->twig_vars['task'] = $this->controller->getTask();
|
|
|
|
$this->grav['twig']->twig_vars['target'] = $this->controller->getTarget();
|
|
|
|
$this->grav['twig']->twig_vars['key'] = $this->controller->getId();
|
|
|
|
|
|
|
|
$this->grav['twig']->twig_vars['flex'] = $this->grav['flex_objects'];
|
|
|
|
$this->grav['twig']->twig_vars['directory'] = $this->controller->getDirectory();
|
|
|
|
$this->grav['twig']->twig_vars['collection'] = $this->controller->getCollection();
|
|
|
|
$this->grav['twig']->twig_vars['object'] = $this->controller->getObject();
|
|
|
|
|
|
|
|
// CSS / JS Assets
|
|
|
|
$this->grav['assets']->addCss('plugin://flex-objects/css/admin.css');
|
|
|
|
$this->grav['assets']->addCss('plugin://admin/themes/grav/css/codemirror/codemirror.css');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|