Skouter mortgage estimates. Web application with view written in PHP and Vue, but controller and models in Go.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 
 
 
 

806 lignes
25 KiB

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