flex-objects.php 24 KB

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