flex-objects.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805
  1. <?php
  2. namespace Grav\Plugin;
  3. use Composer\Autoload\ClassLoader;
  4. use Grav\Common\Debugger;
  5. use Grav\Common\Grav;
  6. use Grav\Common\Page\Interfaces\PageInterface;
  7. use Grav\Common\Page\Pages;
  8. use Grav\Common\Page\Types;
  9. use Grav\Common\Plugin;
  10. use Grav\Common\User\Interfaces\UserInterface;
  11. use Grav\Common\Utils;
  12. use Grav\Events\FlexRegisterEvent;
  13. use Grav\Events\PermissionsRegisterEvent;
  14. use Grav\Events\PluginsLoadedEvent;
  15. use Grav\Framework\Acl\PermissionsReader;
  16. use Grav\Framework\Flex\FlexDirectory;
  17. use Grav\Framework\Flex\FlexForm;
  18. use Grav\Framework\Flex\Interfaces\FlexAuthorizeInterface;
  19. use Grav\Framework\Flex\Interfaces\FlexInterface;
  20. use Grav\Framework\Form\Interfaces\FormInterface;
  21. use Grav\Framework\Route\Route;
  22. use Grav\Plugin\Admin\Admin;
  23. use Grav\Plugin\FlexObjects\Controllers\ObjectController;
  24. use Grav\Plugin\FlexObjects\FlexFormFactory;
  25. use Grav\Plugin\Form\Forms;
  26. use Grav\Plugin\FlexObjects\Admin\AdminController;
  27. use Grav\Plugin\FlexObjects\Flex;
  28. use Psr\Http\Message\ServerRequestInterface;
  29. use RocketTheme\Toolbox\Event\Event;
  30. use function is_array;
  31. use function is_callable;
  32. /**
  33. * Class FlexObjectsPlugin
  34. * @package Grav\Plugin
  35. */
  36. class FlexObjectsPlugin extends Plugin
  37. {
  38. /** @var string */
  39. protected const MIN_GRAV_VERSION = '1.7.0';
  40. /** @var int[] */
  41. public $features = [
  42. 'blueprints' => 1000,
  43. ];
  44. /** @var AdminController */
  45. protected $controller;
  46. /**
  47. * @return bool
  48. */
  49. public static function checkRequirements(): bool
  50. {
  51. return version_compare(GRAV_VERSION, static::MIN_GRAV_VERSION, '>=');
  52. }
  53. /**
  54. * @return array
  55. *
  56. * The getSubscribedEvents() gives the core a list of events
  57. * that the plugin wants to listen to. The key of each
  58. * array section is the event that the plugin listens to
  59. * and the value (in the form of an array) contains the
  60. * callable (or function) as well as the priority. The
  61. * higher the number the higher the priority.
  62. */
  63. public static function getSubscribedEvents(): array
  64. {
  65. if (!static::checkRequirements()) {
  66. return [];
  67. }
  68. return [
  69. PluginsLoadedEvent::class => [
  70. ['initializeFlex', 10]
  71. ],
  72. PermissionsRegisterEvent::class => [
  73. ['onRegisterPermissions', 100]
  74. ],
  75. FlexRegisterEvent::class => [
  76. ['onRegisterFlex', 100]
  77. ],
  78. 'onCliInitialize' => [
  79. ['autoload', 100000],
  80. ['initializeFlex', 10]
  81. ],
  82. 'onPluginsInitialized' => [
  83. ['onPluginsInitialized', 0],
  84. ],
  85. 'onFormRegisterTypes' => [
  86. ['onFormRegisterTypes', 0]
  87. ]
  88. ];
  89. }
  90. /**
  91. * Get list of form field types specified in this plugin. Only special types needs to be listed.
  92. *
  93. * @return array
  94. */
  95. public function getFormFieldTypes()
  96. {
  97. return [
  98. 'list' => [
  99. 'array' => true
  100. ],
  101. 'pagemedia' => [
  102. 'array' => true,
  103. 'media_field' => true,
  104. 'validate' => [
  105. 'type' => 'ignore'
  106. ]
  107. ],
  108. 'filepicker' => [
  109. 'media_picker_field' => true
  110. ],
  111. ];
  112. }
  113. /**
  114. * @return ClassLoader
  115. */
  116. public function autoload(): ClassLoader
  117. {
  118. return require __DIR__ . '/vendor/autoload.php';
  119. }
  120. /**
  121. * [PluginsLoadedEvent:10]: Initialize Flex
  122. *
  123. * @return void
  124. */
  125. public function initializeFlex(): void
  126. {
  127. $config = $this->config->get('plugins.flex-objects.directories') ?? [];
  128. // Add to DI container
  129. $this->grav['flex_objects'] = static function (Grav $grav) use ($config) {
  130. /** @var FlexInterface $flex */
  131. $flex = $grav['flex'];
  132. $flexObjects = new Flex($flex, $config);
  133. // This event is for backwards compatibility only, do not use it!
  134. $grav->fireEvent('onFlexInit', new Event(['flex' => $flexObjects]));
  135. return $flexObjects;
  136. };
  137. }
  138. /**
  139. * Initialize the plugin
  140. *
  141. * @return void
  142. */
  143. public function onPluginsInitialized(): void
  144. {
  145. if ($this->isAdmin()) {
  146. /** @var UserInterface|null $user */
  147. $user = $this->grav['user'] ?? null;
  148. if (null === $user || !$user->authorize('login', 'admin')) {
  149. return;
  150. }
  151. $this->enable([
  152. 'onAdminTwigTemplatePaths' => [
  153. ['onAdminTwigTemplatePaths', 10]
  154. ],
  155. 'onAdminMenu' => [
  156. ['onAdminMenu', 0]
  157. ],
  158. 'onAdminPage' => [
  159. ['onAdminPage', 0]
  160. ],
  161. 'onAdminCompilePresetSCSS' => [
  162. ['onAdminCompilePresetSCSS', 0]
  163. ],
  164. 'onDataTypeExcludeFromDataManagerPluginHook' => [
  165. ['onDataTypeExcludeFromDataManagerPluginHook', 0]
  166. ],
  167. 'onAdminControllerInit' => [
  168. ['onAdminControllerInit', 0]
  169. ],
  170. 'onThemeInitialized' => [
  171. ['onThemeInitialized', 0]
  172. ],
  173. 'onPageInitialized' => [
  174. ['onAdminPageInitialized', 0]
  175. ],
  176. 'onTwigSiteVariables' => [
  177. ['onTwigAdminVariables', 0]
  178. ],
  179. 'onGetPageTemplates' =>
  180. ['onGetPageTemplates', 0]
  181. ]);
  182. } else {
  183. $this->enable([
  184. 'onTwigTemplatePaths' => [
  185. ['onTwigTemplatePaths', 0]
  186. ],
  187. 'onPagesInitialized' => [
  188. ['onPagesInitialized', -10000]
  189. ],
  190. 'onPageInitialized' => [
  191. ['authorizePage', 10000]
  192. ],
  193. 'onBeforeFlexFormInitialize' => [
  194. ['onBeforeFlexFormInitialize', -10]
  195. ],
  196. 'onPageTask' => [
  197. ['onPageTask', -10]
  198. ],
  199. ]);
  200. }
  201. }
  202. /**
  203. * @param FlexRegisterEvent $event
  204. * @return void
  205. */
  206. public function onRegisterFlex(FlexRegisterEvent $event): void
  207. {
  208. /** @var \Grav\Framework\Flex\Flex $flex */
  209. $flex = $event->flex;
  210. $types = (array)$this->config->get('plugins.flex-objects.directories', []);
  211. $this->registerDirectories($flex, $types);
  212. }
  213. /**
  214. * @return void
  215. */
  216. public function onThemeInitialized(): void
  217. {
  218. // Register directories defined in the theme.
  219. /** @var \Grav\Framework\Flex\Flex $flex */
  220. $flex = $this->grav['flex'];
  221. $types = (array)$this->config->get('plugins.flex-objects.directories', []);
  222. $this->registerDirectories($flex, $types, true);
  223. $this->controller = new AdminController();
  224. /** @var Debugger $debugger */
  225. $debugger = Grav::instance()['debugger'];
  226. $names = implode(', ', array_keys($flex->getDirectories()));
  227. $debugger->addMessage(sprintf('Registered flex types: %s', $names), 'debug');
  228. }
  229. /**
  230. * @param Event $event
  231. */
  232. public function onBeforeFlexFormInitialize(Event $event): void
  233. {
  234. /** @var array $form */
  235. $form = $event['form'];
  236. $edit = $form['actions']['edit'] ?? false;
  237. if (!isset($form['flex']['key']) && $edit === true) {
  238. /** @var Route $route */
  239. $route = $this->grav['route'];
  240. $id = rawurldecode($route->getGravParam('id'));
  241. if (null !== $id) {
  242. $form['flex']['key'] = $id;
  243. $event['form'] = $form;
  244. }
  245. }
  246. }
  247. /**
  248. * [onPagesInitialized:-10000] Default router for flex pages.
  249. *
  250. * @param Event $event
  251. */
  252. public function onPagesInitialized(Event $event): void
  253. {
  254. /** @var Route|null $route */
  255. $route = $event['route'] ?? null;
  256. if (null === $route) {
  257. // Stop if in CLI.
  258. return;
  259. }
  260. /** @var PageInterface|null $page */
  261. $page = $this->grav['page'] ?? null;
  262. $base = '';
  263. $path = [];
  264. if (!$page->routable() || $page->template() === 'notfound') {
  265. /** @var Pages $pages */
  266. $pages = $this->grav['pages'];
  267. // Find first existing and routable parent page.
  268. $parts = explode('/', $route->getRoute());
  269. array_shift($parts);
  270. $page = null;
  271. while (!$page && $parts) {
  272. $path[] = array_pop($parts);
  273. $base = '/' . implode('/', $parts);
  274. $page = $pages->find($base);
  275. if ($page && !$page->routable()) {
  276. $page = null;
  277. }
  278. }
  279. }
  280. // If page is found, check if it contains flex directory router.
  281. if ($page) {
  282. $flex = $this->grav['flex'];
  283. $options = $page->header()->flex ?? null;
  284. $router = $options['router'] ?? null;
  285. $type = $options['directory'] ?? null;
  286. $directory = $type ? $flex->getDirectory($type) : null;
  287. if (\is_string($router)) {
  288. $path = implode('/', array_reverse($path));
  289. $response = null;
  290. $flexEvent = new Event([
  291. 'flex' => $flex,
  292. 'directory' => $directory,
  293. 'parent' => $page,
  294. 'page' => $page,
  295. 'base' => $base,
  296. 'path' => $path,
  297. 'route' => $route,
  298. 'options' => $options,
  299. 'request' => $event['request'],
  300. 'response' => &$response,
  301. ]);
  302. $flexEvent = $this->grav->fireEvent("flex.router.{$router}", $flexEvent);
  303. if ($response) {
  304. $this->grav->close($response);
  305. }
  306. /** @var PageInterface|null $routedPage */
  307. $routedPage = $flexEvent['page'];
  308. if ($routedPage) {
  309. /** @var Debugger $debugger */
  310. $debugger = Grav::instance()['debugger'];
  311. $debugger->addMessage(sprintf('Flex uses page %s', $routedPage->route()));
  312. unset($this->grav['page']);
  313. $this->grav['page'] = $routedPage;
  314. $event->stopPropagation();
  315. }
  316. }
  317. }
  318. }
  319. /**
  320. * [onPageInitialized:10000] Authorize Flex Objects Page
  321. *
  322. * @param Event $event
  323. */
  324. public function authorizePage(Event $event): void
  325. {
  326. /** @var PageInterface|null $page */
  327. $page = $event['page'];
  328. if (!$page instanceof PageInterface) {
  329. return;
  330. }
  331. $header = $page->header();
  332. $forms = $page->getForms();
  333. // Update dynamic flex forms from the page.
  334. $form = null;
  335. foreach ($forms as $name => $test) {
  336. $type = $form['type'] ?? null;
  337. if ($type === 'flex') {
  338. $form = $test;
  339. // Update the form and add it back to the page.
  340. $this->grav->fireEvent('onBeforeFlexFormInitialize', new Event(['page' => $page, 'name' => $name, 'form' => &$form]));
  341. $page->addForms([$form], true);
  342. }
  343. }
  344. // Make sure the page contains flex.
  345. $config = $header->flex ?? null;
  346. if (!is_array($config) && !$form) {
  347. return;
  348. }
  349. /** @var Route $route */
  350. $route = $this->grav['route'];
  351. $type = $form['flex']['type'] ?? $config['directory'] ?? $route->getGravParam('directory') ?? null;
  352. $key = $form['flex']['key'] ?? $config['id'] ?? $route->getGravParam('id') ?? '';
  353. if (\is_string($type)) {
  354. /** @var Flex $flex */
  355. $flex = $this->grav['flex_objects'];
  356. $directory = $flex->getDirectory($type);
  357. } else {
  358. $directory = null;
  359. }
  360. if (!$directory) {
  361. return;
  362. }
  363. $create = (bool)($form['actions']['create'] ?? false);
  364. $edit = (bool)($form['actions']['edit'] ?? false);
  365. $scope = $config['access']['scope'] ?? null;
  366. $object = $key !== '' ? $directory->getObject($key) : null;
  367. $hasAccess = null;
  368. $action = $config['access']['action'] ?? null;
  369. if (null === $action) {
  370. if (!$form) {
  371. $action = $key !== '' ? 'read' : 'list';
  372. if (null === $scope) {
  373. $hasAccess = true;
  374. }
  375. } elseif ($object) {
  376. if ($edit) {
  377. $scope = $scope ?? 'admin';
  378. $action = 'update';
  379. } else {
  380. $hasAccess = false;
  381. }
  382. } elseif ($create) {
  383. $object = $directory->createObject([], $key);
  384. $scope = $scope ?? 'admin';
  385. $action = 'create';
  386. } else {
  387. $hasAccess = false;
  388. }
  389. }
  390. if ($action && $hasAccess === null) {
  391. if ($object instanceof FlexAuthorizeInterface) {
  392. $hasAccess = $object->isAuthorized($action, $scope);
  393. } else {
  394. $hasAccess = $directory->isAuthorized($action, $scope);
  395. }
  396. }
  397. if (!$hasAccess) {
  398. // Hide the page (404).
  399. $page->routable(false);
  400. $page->visible(false);
  401. // If page is not a module, replace the current page with unauthorized page.
  402. if (!$page->isModule()) {
  403. $login = $this->grav['login'] ?? null;
  404. $unauthorized = $login ? $login->addPage('unauthorized') : null;
  405. if ($unauthorized) {
  406. unset($this->grav['page']);
  407. $this->grav['page'] = $unauthorized;
  408. }
  409. }
  410. } elseif ($config['access']['override'] ?? false) {
  411. // Override page access settings (allow).
  412. $page->modifyHeader('access', []);
  413. }
  414. }
  415. /**
  416. * @param Event $event
  417. */
  418. public function onPageTask(Event $event): void
  419. {
  420. /** @var FormInterface|null $form */
  421. $form = $event['form'] ?? null;
  422. if (!$form instanceof FlexForm) {
  423. return;
  424. }
  425. $object = $form->getObject();
  426. /** @var ServerRequestInterface $request */
  427. $request = $event['request'];
  428. $request = $request
  429. ->withAttribute('type', $object->getFlexType())
  430. ->withAttribute('key', $object->getKey())
  431. ->withAttribute('object', $object)
  432. ->withAttribute('form', $form);
  433. $controller = new ObjectController();
  434. $response = $controller->handle($request);
  435. if ($response->getStatusCode() !== 418) {
  436. $this->grav->close($response);
  437. }
  438. }
  439. /**
  440. * @param \Grav\Framework\Flex\Flex $flex
  441. * @param array $types
  442. * @param bool $report
  443. */
  444. protected function registerDirectories(\Grav\Framework\Flex\Flex $flex, array $types, bool $report = false): void
  445. {
  446. $map = Flex::getLegacyBlueprintMap(false);
  447. foreach ($types as $blueprint) {
  448. // Backwards compatibility to v1.0.0-rc.3
  449. $blueprint = $map[$blueprint] ?? $blueprint;
  450. $type = Utils::basename((string)$blueprint, '.yaml');
  451. if (!$type) {
  452. continue;
  453. }
  454. if (!file_exists($blueprint)) {
  455. if ($report) {
  456. /** @var Debugger $debugger */
  457. $debugger = Grav::instance()['debugger'];
  458. $debugger->addMessage(sprintf('Flex: blueprint for flex type %s is missing', $type), 'error');
  459. }
  460. continue;
  461. }
  462. $directory = $flex->getDirectory($type);
  463. if (!$directory || !$directory->isEnabled()) {
  464. $flex->addDirectoryType($type, $blueprint);
  465. }
  466. }
  467. }
  468. /**
  469. * Initial stab at registering permissions (WIP)
  470. *
  471. * @param PermissionsRegisterEvent $event
  472. * @return void
  473. */
  474. public function onRegisterPermissions(PermissionsRegisterEvent $event): void
  475. {
  476. /** @var Flex $flex */
  477. $flex = $this->grav['flex_objects'];
  478. $directories = $flex->getDirectories();
  479. $permissions = $event->permissions;
  480. $actions = [];
  481. foreach ($directories as $directory) {
  482. $data = $directory->getConfig('admin.permissions', []);
  483. $actions[] = PermissionsReader::fromArray($data, $permissions->getTypes());
  484. }
  485. $actions[] = PermissionsReader::fromYaml("plugin://{$this->name}/permissions.yaml");
  486. $permissions->addActions(array_replace(...$actions));
  487. }
  488. /**
  489. * @param Event $event
  490. * @return void
  491. */
  492. public function onFormRegisterTypes(Event $event): void
  493. {
  494. /** @var Forms $forms */
  495. $forms = $event['forms'];
  496. $forms->registerType('flex', new FlexFormFactory());
  497. }
  498. /**
  499. * @param Event $event
  500. * @return void
  501. */
  502. public function onAdminPage(Event $event): void
  503. {
  504. if ($this->controller->isActive()) {
  505. $event->stopPropagation();
  506. /** @var PageInterface $page */
  507. $page = $event['page'];
  508. $page->init(new \SplFileInfo(__DIR__ . '/admin/pages/flex-objects.md'));
  509. $page->slug($this->controller->getLocation());
  510. $header = $page->header();
  511. $header->access = ['admin.login'];
  512. $header->controller = $this->controller->getInfo();
  513. }
  514. }
  515. /**
  516. * [onPageInitialized:0]: Run controller
  517. *
  518. * @return void
  519. */
  520. public function onAdminPageInitialized(): void
  521. {
  522. if ($this->controller->isActive()) {
  523. $this->controller->execute();
  524. $this->controller->redirect();
  525. }
  526. }
  527. /**
  528. * @param Event $event
  529. * @return void
  530. */
  531. public function onAdminControllerInit(Event $event): void
  532. {
  533. $eventController = $event['controller'];
  534. // Blacklist all admin routes, including aliases and redirects.
  535. $eventController->blacklist_views[] = 'flex-objects';
  536. foreach ($this->controller->getAdminRoutes() as $route => $info) {
  537. $eventController->blacklist_views[] = trim($route, '/');
  538. }
  539. }
  540. /**
  541. * Add Flex-Object's preset.scss to the Admin Preset SCSS compile process
  542. *
  543. * @param Event $event
  544. * @return void
  545. */
  546. public function onAdminCompilePresetSCSS(Event $event): void
  547. {
  548. $event['scss']->add($this->grav['locator']->findResource('plugins://flex-objects/scss/_preset.scss'));
  549. }
  550. /**
  551. * @param Event $event
  552. * @return void
  553. */
  554. public function onGetPageTemplates(Event $event): void
  555. {
  556. /** @var Types $types */
  557. $types = $event->types;
  558. $types->register('flex-objects', 'plugins://flex-objects/blueprints/pages/flex-objects.yaml');
  559. }
  560. /**
  561. * Form select options listing all enabled directories.
  562. *
  563. * @return array
  564. */
  565. public static function directoryOptions(): array
  566. {
  567. /** @var Flex $flex */
  568. $flex = Grav::instance()['flex_objects'];
  569. $directories = $flex->getDirectories();
  570. $list = [];
  571. /**
  572. * @var string $type
  573. * @var FlexDirectory $directory
  574. */
  575. foreach ($directories as $type => $directory) {
  576. if (!$directory->getConfig('site.hidden')) {
  577. $list[$type] = $directory->getTitle();
  578. }
  579. }
  580. return $list;
  581. }
  582. /**
  583. * @return array
  584. */
  585. public function getAdminMenu(): array
  586. {
  587. /** @var Flex $flex */
  588. $flex = $this->grav['flex_objects'];
  589. $list = [];
  590. foreach ($flex->getAdminMenuItems() as $name => $item) {
  591. $route = trim($item['route'] ?? $name, '/');
  592. $list[$route] = $item;
  593. }
  594. return $list;
  595. }
  596. /**
  597. * Add Flex Directory to admin menu
  598. *
  599. * @return void
  600. */
  601. public function onAdminMenu(): void
  602. {
  603. /** @var Flex $flex */
  604. $flex = $this->grav['flex_objects'];
  605. /** @var Admin $admin */
  606. $admin = $this->grav['admin'];
  607. foreach ($this->getAdminMenu() as $route => $item) {
  608. $directory = null;
  609. if (isset($item['directory'])) {
  610. $directory = $flex->getDirectory($item['directory']);
  611. if (!$directory || !$directory->isEnabled()) {
  612. continue;
  613. }
  614. }
  615. $title = $item['title'] ?? 'PLUGIN_FLEX_OBJECTS.TITLE';
  616. $index = $item['index'] ?? 0;
  617. if (($this->grav['twig']->plugins_hooked_nav[$title]['index'] ?? 1000) <= $index) {
  618. continue;
  619. }
  620. $location = $item['location'] ?? $route;
  621. $hidden = $item['hidden'] ?? false;
  622. $icon = $item['icon'] ?? 'fa-list';
  623. $authorize = $item['authorize'] ?? ($directory ? null : ['admin.flex-objects', 'admin.super']);
  624. if ($hidden || (null === $authorize && $directory->isAuthorized('list', 'admin', $admin->user))) {
  625. continue;
  626. }
  627. $cache = $directory ? $directory->getCache('index') : null;
  628. $count = $cache ? $cache->get('admin-count-' . md5($admin->user->username)) : false;
  629. if (null === $count) {
  630. try {
  631. $collection = $directory->getCollection();
  632. if (is_callable([$collection, 'isAuthorized'])) {
  633. $count = $collection->isAuthorized('list', 'admin', $admin->user)->count();
  634. } else {
  635. $count = $collection->count();
  636. }
  637. $cache->set('admin-count-' . md5($admin->user->username), $count);
  638. } catch (\InvalidArgumentException $e) {
  639. continue;
  640. }
  641. }
  642. $badge = $directory ? ['badge' => ['count' => $count]] : [];
  643. $priority = $item['priority'] ?? 0;
  644. $this->grav['twig']->plugins_hooked_nav[$title] = [
  645. 'location' => $location,
  646. 'route' => $route,
  647. 'index' => $index,
  648. 'icon' => $icon,
  649. 'authorize' => $authorize,
  650. 'priority' => $priority
  651. ] + $badge;
  652. }
  653. }
  654. /**
  655. * Exclude Flex Directory data from the Data Manager plugin
  656. *
  657. * @return void
  658. */
  659. public function onDataTypeExcludeFromDataManagerPluginHook(): void
  660. {
  661. $this->grav['admin']->dataTypesExcludedFromDataManagerPlugin[] = 'flex-objects';
  662. }
  663. /**
  664. * Add current directory to twig lookup paths.
  665. *
  666. * @return void
  667. */
  668. public function onTwigTemplatePaths(): void
  669. {
  670. $extra_site_twig_path = $this->config->get('plugins.flex-objects.extra_site_twig_path');
  671. $extra_path = $extra_site_twig_path ? $this->grav['locator']->findResource($extra_site_twig_path) : null;
  672. if ($extra_path) {
  673. $this->grav['twig']->twig_paths[] = $extra_path;
  674. }
  675. $this->grav['twig']->twig_paths[] = __DIR__ . '/templates';
  676. }
  677. /**
  678. * Add plugin templates path
  679. *
  680. * @param Event $event
  681. * @return void
  682. */
  683. public function onAdminTwigTemplatePaths(Event $event): void
  684. {
  685. $extra_admin_twig_path = $this->config->get('plugins.flex-objects.extra_admin_twig_path');
  686. $extra_path = $extra_admin_twig_path ? $this->grav['locator']->findResource($extra_admin_twig_path) : null;
  687. $paths = $event['paths'];
  688. if ($extra_path) {
  689. $paths[] = $extra_path;
  690. }
  691. $paths[] = __DIR__ . '/admin/templates';
  692. $event['paths'] = $paths;
  693. }
  694. /**
  695. * Set needed variables to display directory.
  696. *
  697. * @return void
  698. */
  699. public function onTwigAdminVariables(): void
  700. {
  701. if ($this->controller->isActive()) {
  702. // Twig shortcuts
  703. $this->grav['twig']->twig_vars['controller'] = $this->controller;
  704. $this->grav['twig']->twig_vars['action'] = $this->controller->getAction();
  705. $this->grav['twig']->twig_vars['task'] = $this->controller->getTask();
  706. $this->grav['twig']->twig_vars['target'] = $this->controller->getTarget();
  707. $this->grav['twig']->twig_vars['key'] = $this->controller->getId();
  708. $this->grav['twig']->twig_vars['flex'] = $this->grav['flex_objects'];
  709. $this->grav['twig']->twig_vars['directory'] = $this->controller->getDirectory();
  710. $this->grav['twig']->twig_vars['collection'] = $this->controller->getCollection();
  711. $this->grav['twig']->twig_vars['object'] = $this->controller->getObject();
  712. // CSS / JS Assets
  713. $this->grav['assets']->addCss('plugin://flex-objects/css/admin.css');
  714. $this->grav['assets']->addCss('plugin://admin/themes/grav/css/codemirror/codemirror.css');
  715. }
  716. }
  717. }