From 58533c495c94b90a5fbf0c59b7060d99e372d47e Mon Sep 17 00:00:00 2001 From: Matias Griese Date: Thu, 11 Mar 2021 12:34:37 +0200 Subject: [PATCH] Added full blueprint support and `Theme::getFormFieldTypes()` just like in plugins --- CHANGELOG.md | 2 + system/src/Grav/Common/Page/Pages.php | 9 ++- system/src/Grav/Common/Page/Types.php | 34 +++++++---- system/src/Grav/Common/Plugin.php | 87 ++++++++++++++++----------- system/src/Grav/Common/Plugins.php | 18 ++++-- system/src/Grav/Common/Theme.php | 50 +++++---------- system/src/Grav/Common/Themes.php | 21 ++++++- 7 files changed, 130 insertions(+), 91 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 170c39c9e..0c273ad44 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,8 @@ 1. [](#new) * Added `ControllerResponseTrait::createDownloadResponse()` method + * Added full blueprint support to theme if you move existing files in `blueprints/` to `blueprints/pages/` folder [#3255](https://github.com/getgrav/grav/issues/3255) + * Added support for `Theme::getFormFieldTypes()` just like in plugins 1. [](#improved) * Optimized `Flex Pages` for speed * Optimized saving visible/ordered pages when there are a lot of siblings [#3231](https://github.com/getgrav/grav/issues/3231) diff --git a/system/src/Grav/Common/Page/Pages.php b/system/src/Grav/Common/Page/Pages.php index a04cc7890..4f645025c 100644 --- a/system/src/Grav/Common/Page/Pages.php +++ b/system/src/Grav/Common/Page/Pages.php @@ -1174,7 +1174,14 @@ class Pages $event->types = $types; $grav->fireEvent('onGetPageBlueprints', $event); - $types->scanBlueprints('theme://blueprints/'); + $types->init(); + + // Try new location first. + $lookup = 'theme://blueprints/pages/'; + if (!is_dir($lookup)) { + $lookup = 'theme://blueprints/'; + } + $types->scanBlueprints($lookup); // Scan templates $event = new Event(); diff --git a/system/src/Grav/Common/Page/Types.php b/system/src/Grav/Common/Page/Types.php index 051610f6b..b9d8f9551 100644 --- a/system/src/Grav/Common/Page/Types.php +++ b/system/src/Grav/Common/Page/Types.php @@ -32,22 +32,23 @@ class Types implements \ArrayAccess, \Iterator, \Countable /** @var array */ protected $items; /** @var array */ - protected $systemBlueprints; + protected $systemBlueprints = []; /** * @param string $type * @param Blueprint|null $blueprint + * @return void */ public function register($type, $blueprint = null) { if (!isset($this->items[$type])) { $this->items[$type] = []; - } elseif (!$blueprint) { + } elseif (null === $blueprint) { return; } - if (!$blueprint && $this->systemBlueprints) { - $blueprint = $this->systemBlueprints[$type] ?? $this->systemBlueprints['default']; + if (null === $blueprint) { + $blueprint = $this->systemBlueprints[$type] ?? $this->systemBlueprints['default'] ?? null; } if ($blueprint) { @@ -55,8 +56,23 @@ class Types implements \ArrayAccess, \Iterator, \Countable } } + /** + * @return void + */ + public function init() + { + if (null === $this->systemBlueprints) { + // Register all blueprints from the blueprints stream. + $this->systemBlueprints = $this->findBlueprints('blueprints://pages'); + foreach ($this->systemBlueprints as $type => $blueprint) { + $this->register($type); + } + } + } + /** * @param string $uri + * @return void */ public function scanBlueprints($uri) { @@ -64,15 +80,6 @@ class Types implements \ArrayAccess, \Iterator, \Countable throw new InvalidArgumentException('First parameter must be URI'); } - if (null === $this->systemBlueprints) { - $this->systemBlueprints = $this->findBlueprints('blueprints://pages'); - - // Register default by default. - $this->register('default'); - - $this->register('external'); - } - foreach ($this->findBlueprints($uri) as $type => $blueprint) { $this->register($type, $blueprint); } @@ -80,6 +87,7 @@ class Types implements \ArrayAccess, \Iterator, \Countable /** * @param string $uri + * @return void */ public function scanTemplates($uri) { diff --git a/system/src/Grav/Common/Plugin.php b/system/src/Grav/Common/Plugin.php index d075860f4..65b11dba1 100644 --- a/system/src/Grav/Common/Plugin.php +++ b/system/src/Grav/Common/Plugin.php @@ -16,6 +16,7 @@ use Grav\Common\Page\Interfaces\PageInterface; use Grav\Common\Config\Config; use LogicException; use RocketTheme\Toolbox\File\YamlFile; +use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventSubscriberInterface; use function defined; @@ -35,11 +36,11 @@ class Plugin implements EventSubscriberInterface, ArrayAccess /** @var Grav */ protected $grav; - /** @var Config */ + /** @var Config|null */ protected $config; /** @var bool */ protected $active = true; - /** @var Blueprint */ + /** @var Blueprint|null */ protected $blueprint; /** @@ -127,21 +128,25 @@ class Plugin implements EventSubscriberInterface, ArrayAccess */ protected function isPluginActiveAdmin($plugin_route) { - $should_run = false; + $active = false; + /** @var Uri $uri */ $uri = $this->grav['uri']; + /** @var Config $config */ + $config = $this->config ?? $this->grav['config']; - if (strpos($uri->path(), $this->config->get('plugins.admin.route') . '/' . $plugin_route) === false) { - $should_run = false; + if (strpos($uri->path(), $config->get('plugins.admin.route') . '/' . $plugin_route) === false) { + $active = false; } elseif (isset($uri->paths()[1]) && $uri->paths()[1] === $plugin_route) { - $should_run = true; + $active = true; } - return $should_run; + return $active; } /** * @param array $events + * @return void */ protected function enable(array $events) { @@ -164,22 +169,18 @@ class Plugin implements EventSubscriberInterface, ArrayAccess /** * @param array $params * @param string $eventName + * @return int */ private function getPriority($params, $eventName) { - $grav = Grav::instance(); $override = implode('.', ['priorities', $this->name, $eventName, $params[0]]); - if ($grav['config']->get($override) !== null) { - return $grav['config']->get($override); - } - if (isset($params[1])) { - return $params[1]; - } - return 0; + + return $this->grav['config']->get($override) ?? $params[1] ?? 0; } /** * @param array $events + * @return void */ protected function disable(array $events) { @@ -207,12 +208,13 @@ class Plugin implements EventSubscriberInterface, ArrayAccess */ public function offsetExists($offset) { - $this->loadBlueprint(); - if ($offset === 'title') { $offset = 'name'; } - return isset($this->blueprint[$offset]); + + $blueprint = $this->getBlueprint(); + + return isset($blueprint[$offset]); } /** @@ -223,12 +225,13 @@ class Plugin implements EventSubscriberInterface, ArrayAccess */ public function offsetGet($offset) { - $this->loadBlueprint(); - if ($offset === 'title') { $offset = 'name'; } - return $this->blueprint[$offset] ?? null; + + $blueprint = $this->getBlueprint(); + + return $blueprint[$offset] ?? null; } /** @@ -281,9 +284,12 @@ class Plugin implements EventSubscriberInterface, ArrayAccess */ protected function parseLinks($content, $function, $internal_regex = '(.*)') { - $regex = '/\[plugin:(?:' . $this->name . ')\]\(' . $internal_regex . '\)/i'; + $regex = '/\[plugin:(?:' . preg_quote($this->name, '/') . ')\]\(' . $internal_regex . '\)/i'; - return preg_replace_callback($regex, $function, $content); + $result = preg_replace_callback($regex, $function, $content); + \assert($result !== null); + + return $result; } /** @@ -301,9 +307,12 @@ class Plugin implements EventSubscriberInterface, ArrayAccess */ protected function mergeConfig(PageInterface $page, $deep = false, $params = [], $type = 'plugins') { + /** @var Config $config */ + $config = $this->config ?? $this->grav['config']; + $class_name = $this->name; $class_name_merged = $class_name . '.merged'; - $defaults = $this->config->get($type . '.' . $class_name, []); + $defaults = $config->get($type . '.' . $class_name, []); $page_header = $page->header(); $header = []; @@ -356,23 +365,26 @@ class Plugin implements EventSubscriberInterface, ArrayAccess /** * Persists to disk the plugin parameters currently stored in the Grav Config object * - * @param string $plugin_name The name of the plugin whose config it should store. - * + * @param string $name The name of the plugin whose config it should store. * @return bool */ - public static function saveConfig($plugin_name) + public static function saveConfig($name) { - if (!$plugin_name) { + if (!$name) { return false; } $grav = Grav::instance(); + + /** @var UniformResourceLocator $locator */ $locator = $grav['locator']; - $filename = 'config://plugins/' . $plugin_name . '.yaml'; - $file = YamlFile::instance($locator->findResource($filename, true, true)); - $content = $grav['config']->get('plugins.' . $plugin_name); + + $filename = 'config://plugins/' . $name . '.yaml'; + $file = YamlFile::instance((string)$locator->findResource($filename, true, true)); + $content = $grav['config']->get('plugins.' . $name); $file->save($content); $file->free(); + unset($file); return true; } @@ -384,21 +396,28 @@ class Plugin implements EventSubscriberInterface, ArrayAccess */ public function getBlueprint() { - if (!$this->blueprint) { + if (null === $this->blueprint) { $this->loadBlueprint(); + \assert($this->blueprint instanceof Blueprint); } + return $this->blueprint; } /** * Load blueprints. + * + * @return void */ protected function loadBlueprint() { - if (!$this->blueprint) { + if (null === $this->blueprint) { $grav = Grav::instance(); + /** @var Plugins $plugins */ $plugins = $grav['plugins']; - $this->blueprint = $plugins->get($this->name)->blueprints(); + $data = $plugins->get($this->name); + \assert($data !== null); + $this->blueprint = $data->blueprints(); } } } diff --git a/system/src/Grav/Common/Plugins.php b/system/src/Grav/Common/Plugins.php index 4e0afea30..be8f43bc2 100644 --- a/system/src/Grav/Common/Plugins.php +++ b/system/src/Grav/Common/Plugins.php @@ -17,6 +17,7 @@ use Grav\Common\File\CompiledYamlFile; use Grav\Events\PluginsLoadedEvent; use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; use RuntimeException; +use SplFileInfo; use Symfony\Component\EventDispatcher\EventDispatcher; use function get_class; use function is_object; @@ -27,7 +28,7 @@ use function is_object; */ class Plugins extends Iterator { - /** @var array */ + /** @var array|null */ public $formFieldTypes; /** @var bool */ @@ -46,6 +47,7 @@ class Plugins extends Iterator $iterator = $locator->getIterator('plugins://'); $plugins = []; + /** @var SplFileInfo $directory */ foreach ($iterator as $directory) { if (!$directory->isDir()) { continue; @@ -56,7 +58,10 @@ class Plugins extends Iterator sort($plugins, SORT_NATURAL | SORT_FLAG_CASE); foreach ($plugins as $plugin) { - $this->add($this->loadPlugin($plugin)); + $object = $this->loadPlugin($plugin); + if ($object) { + $this->add($object); + } } } @@ -158,6 +163,7 @@ class Plugins extends Iterator * Add a plugin * * @param Plugin $plugin + * @return void */ public function add($plugin) { @@ -183,8 +189,8 @@ class Plugins extends Iterator */ public static function getPlugins(): array { - $grav = Grav::instance(); - $plugins = $grav['plugins']; + /** @var Plugins $plugins */ + $plugins = Grav::instance()['plugins']; $list = []; foreach ($plugins as $instance) { @@ -208,11 +214,13 @@ class Plugins extends Iterator /** * Return list of all plugin data with their blueprints. * - * @return array + * @return Data[] */ public static function all() { $grav = Grav::instance(); + + /** @var Plugins $plugins */ $plugins = $grav['plugins']; $list = []; diff --git a/system/src/Grav/Common/Theme.php b/system/src/Grav/Common/Theme.php index 2b807b611..a5006a215 100644 --- a/system/src/Grav/Common/Theme.php +++ b/system/src/Grav/Common/Theme.php @@ -9,9 +9,9 @@ namespace Grav\Common; -use Grav\Common\Page\Interfaces\PageInterface; use Grav\Common\Config\Config; use RocketTheme\Toolbox\File\YamlFile; +use RocketTheme\Toolbox\ResourceLocator\UniformResourceLocator; /** * Class Theme @@ -44,53 +44,30 @@ class Theme extends Plugin /** * Persists to disk the theme parameters currently stored in the Grav Config object * - * @param string $theme_name The name of the theme whose config it should store. + * @param string $name The name of the theme whose config it should store. * @return bool */ - public static function saveConfig($theme_name) + public static function saveConfig($name) { - if (!$theme_name) { + if (!$name) { return false; } $grav = Grav::instance(); + + /** @var UniformResourceLocator $locator */ $locator = $grav['locator']; - $filename = 'config://themes/' . $theme_name . '.yaml'; - $file = YamlFile::instance($locator->findResource($filename, true, true)); - $content = $grav['config']->get('themes.' . $theme_name); + + $filename = 'config://themes/' . $name . '.yaml'; + $file = YamlFile::instance((string)$locator->findResource($filename, true, true)); + $content = $grav['config']->get('themes.' . $name); $file->save($content); $file->free(); + unset($file); return true; } - /** - * Override the mergeConfig method to work for themes - * - * @param PageInterface $page - * @param string $deep - * @param array $params - * @param string $type - * @return Data\Data - */ - protected function mergeConfig(PageInterface $page, $deep = 'merge', $params = [], $type = 'themes') - { - return parent::mergeConfig($page, $deep, $params, $type); - } - - /** - * Simpler getter for the theme blueprint - * - * @return mixed - */ - public function getBlueprint() - { - if (!$this->blueprint) { - $this->loadBlueprint(); - } - return $this->blueprint; - } - /** * Load blueprints. * @@ -100,8 +77,11 @@ class Theme extends Plugin { if (!$this->blueprint) { $grav = Grav::instance(); + /** @var Themes $themes */ $themes = $grav['themes']; - $this->blueprint = $themes->get($this->name)->blueprints(); + $data = $themes->get($this->name); + \assert($data !== null); + $this->blueprint = $data->blueprints(); } } } diff --git a/system/src/Grav/Common/Themes.php b/system/src/Grav/Common/Themes.php index 6adeea09e..bf155ede5 100644 --- a/system/src/Grav/Common/Themes.php +++ b/system/src/Grav/Common/Themes.php @@ -33,10 +33,8 @@ class Themes extends Iterator { /** @var Grav */ protected $grav; - /** @var Config */ protected $config; - /** @var bool */ protected $inited = false; @@ -95,6 +93,20 @@ class Themes extends Iterator $events->addSubscriber($instance); } + // Register blueprints. + if (is_dir('theme://blueprints/pages')) { + /** @var UniformResourceLocator $locator */ + $locator = $this->grav['locator']; + $locator->addPath('blueprints', '', ['theme://blueprints'], ['user', 'blueprints']); + } + + // Register form fields. + if (method_exists($instance, 'getFormFieldTypes')) { + /** @var Plugins $plugins */ + $plugins = $this->grav['plugins']; + $plugins->formFieldTypes = $instance->getFormFieldTypes() + $plugins->formFieldTypes; + } + $this->grav['theme'] = $instance; $this->grav->fireEvent('onThemeInitialized'); @@ -382,7 +394,10 @@ class Themes extends Iterator } // Try Old style theme classes - $path = strtolower(preg_replace('#\\\|_(?!.+\\\)#', '/', $class)); + $path = preg_replace('#\\\|_(?!.+\\\)#', '/', $class); + \assert(null !== $path); + + $path = strtolower($path); $file = $locator("themes://{$path}/theme.php") ?: $locator("themes://{$path}/{$path}.php"); // Load class