From 57f2a259c7beeb9d7902a47ebaa6db8890647d56 Mon Sep 17 00:00:00 2001 From: uros_g Date: Tue, 1 Jun 2021 02:08:00 +0200 Subject: [PATCH] =?UTF-8?q?odve=C4=8Dne=20.gitignore=20fajle=20zbrisal?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 4 - assets/.gitignore | 1 - config/.gitignore | 1 - content/.gitignore | 1 - plugins/.gitignore | 2 - plugins/PicoDeprecated/CHANGELOG.md | 155 +++++++ plugins/PicoDeprecated/LICENSE | 21 + plugins/PicoDeprecated/PicoDeprecated.php | 383 ++++++++++++++++++ plugins/PicoDeprecated/README.md | 44 ++ plugins/PicoDeprecated/composer.json | 41 ++ .../lib/AbstractPicoCompatPlugin.php | 101 +++++ .../lib/AbstractPicoPluginApiCompatPlugin.php | 83 ++++ .../lib/PicoCompatPluginInterface.php | 62 +++ .../PicoPluginApiCompatPluginInterface.php | 37 ++ .../plugins/PicoMainCompatPlugin.php | 102 +++++ .../plugins/PicoPluginApi0CompatPlugin.php | 314 ++++++++++++++ .../plugins/PicoPluginApi1CompatPlugin.php | 347 ++++++++++++++++ .../plugins/PicoPluginApi2CompatPlugin.php | 131 ++++++ .../plugins/PicoThemeApi0CompatPlugin.php | 52 +++ .../plugins/PicoThemeApi1CompatPlugin.php | 154 +++++++ .../plugins/PicoThemeApi2CompatPlugin.php | 205 ++++++++++ vendor/erusev/parsedown-extra/.gitignore | 2 - vendor/picocms/composer-installer/.gitignore | 16 - vendor/symfony/yaml/.gitignore | 3 - vendor/twig/twig/.gitignore | 5 - vendor/twig/twig/ext/twig/.gitignore | 30 -- 26 files changed, 2232 insertions(+), 65 deletions(-) delete mode 100644 assets/.gitignore delete mode 100644 config/.gitignore delete mode 100644 content/.gitignore delete mode 100644 plugins/.gitignore create mode 100644 plugins/PicoDeprecated/CHANGELOG.md create mode 100644 plugins/PicoDeprecated/LICENSE create mode 100644 plugins/PicoDeprecated/PicoDeprecated.php create mode 100644 plugins/PicoDeprecated/README.md create mode 100644 plugins/PicoDeprecated/composer.json create mode 100644 plugins/PicoDeprecated/lib/AbstractPicoCompatPlugin.php create mode 100644 plugins/PicoDeprecated/lib/AbstractPicoPluginApiCompatPlugin.php create mode 100644 plugins/PicoDeprecated/lib/PicoCompatPluginInterface.php create mode 100644 plugins/PicoDeprecated/lib/PicoPluginApiCompatPluginInterface.php create mode 100644 plugins/PicoDeprecated/plugins/PicoMainCompatPlugin.php create mode 100644 plugins/PicoDeprecated/plugins/PicoPluginApi0CompatPlugin.php create mode 100644 plugins/PicoDeprecated/plugins/PicoPluginApi1CompatPlugin.php create mode 100644 plugins/PicoDeprecated/plugins/PicoPluginApi2CompatPlugin.php create mode 100644 plugins/PicoDeprecated/plugins/PicoThemeApi0CompatPlugin.php create mode 100644 plugins/PicoDeprecated/plugins/PicoThemeApi1CompatPlugin.php create mode 100644 plugins/PicoDeprecated/plugins/PicoThemeApi2CompatPlugin.php delete mode 100644 vendor/erusev/parsedown-extra/.gitignore delete mode 100644 vendor/picocms/composer-installer/.gitignore delete mode 100644 vendor/symfony/yaml/.gitignore delete mode 100644 vendor/twig/twig/.gitignore delete mode 100644 vendor/twig/twig/ext/twig/.gitignore diff --git a/.gitignore b/.gitignore index 5f15152..65cc4af 100644 --- a/.gitignore +++ b/.gitignore @@ -16,7 +16,3 @@ desktop.ini # Mac OS X .DS_Store ._* - -# Composer -/composer.phar -/vendor diff --git a/assets/.gitignore b/assets/.gitignore deleted file mode 100644 index 71beeb7..0000000 --- a/assets/.gitignore +++ /dev/null @@ -1 +0,0 @@ -# This file is meant to be empty diff --git a/config/.gitignore b/config/.gitignore deleted file mode 100644 index 71beeb7..0000000 --- a/config/.gitignore +++ /dev/null @@ -1 +0,0 @@ -# This file is meant to be empty diff --git a/content/.gitignore b/content/.gitignore deleted file mode 100644 index 71beeb7..0000000 --- a/content/.gitignore +++ /dev/null @@ -1 +0,0 @@ -# This file is meant to be empty diff --git a/plugins/.gitignore b/plugins/.gitignore deleted file mode 100644 index a9f7294..0000000 --- a/plugins/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# You should add plugins installed by Composer here -/PicoDeprecated diff --git a/plugins/PicoDeprecated/CHANGELOG.md b/plugins/PicoDeprecated/CHANGELOG.md new file mode 100644 index 0000000..4cc5d1d --- /dev/null +++ b/plugins/PicoDeprecated/CHANGELOG.md @@ -0,0 +1,155 @@ +Pico Deprecated Changelog +========================= + +**Note:** This changelog only provides technical information about the changes + introduced with a particular Pico version, and is meant to supplement + the actual code changes. The information in this changelog are often + insufficient to understand the implications of larger changes. Please + refer to both the UPGRADE and NEWS sections of the docs for more + details. + +**Note:** Changes breaking backwards compatibility (BC) are marked with an `!` + (exclamation mark). This doesn't include changes for which BC is + preserved by this plugin. If a previously deprecated feature is later + removed, this change is going to be marked as BC-breaking change. + Please note that BC-breaking changes are only possible with a new + major version. + +**Note:** Many versions of `PicoDeprecated` include changes which are not + explicitly mentioned in this changelog. This primarily concerns + changes in Pico's plugin API. These changes aren't listed separately + because they are already listed in Pico's changelog. Only functional + changes and/or BC-breaking changes are listed below. + +### Version 2.1.4 +Released: 2020-08-29 + +No changes + +### Version 2.1.3 +Released: 2020-07-10 + +No changes + +### Version 2.1.2 +Released: 2020-04-10 + +No changes + +### Version 2.1.1 +Released: 2019-12-31 + +No changes + +### Version 2.1.0 +Released: 2019-11-24 + +No changes + +### Version 2.1.0-beta.1 +Released: 2019-11-03 + +``` +* [New] Add support for the latest API v3 changes +* [New] Support disabled Twig autoescape prior to API v3 +* [New] Re-introduce `theme_url` config variable +* [New] Re-introduce `prev_page`, `base_dir` and `theme_dir` Twig variables +* [New] Support loading additional plugins using API v1 `onPluginsLoaded` event +* [New] Re-introduce Pico v0.9 config constant `CACHE_DIR` +* [New] Add release & build system to test the plugin using PHP_CodeSniffer and + to automatically create pre-built release packages +* [Changed] Split the plugin's functionality into multiple compatibility + plugins (two for each API version, for plugins and themes resp.) + and load the necessary compatibility plugins on demand only; also + allow 3rd-party plugins to load their own compatibility plugins +``` + +### Version 2.0.5-beta.1 +Released: 2019-01-03 + +``` +* [New] Add `2.0.x-dev` alias for master branch to `composer.json` +``` + +### Version 2.0.4 +Released: 2018-12-17 + +No changes + +### Version 2.0.3 +Released: 2018-12-03 + +No changes + +### Version 2.0.2 +Released: 2018-08-12 + +No changes + +### Version 2.0.1 +Released: 2018-07-29 + +No changes + +### Version 2.0.0 +Released: 2018-07-01 + +No changes + +### Version 2.0.0-beta.3 +Released: 2018-04-07 + +No changes + +### Version 2.0.0-beta.2 +Released: 2018-01-21 + +``` +* [New] Add support for the latest API v2 changes +* [New] ! Add support for themes using the old `.html` file extension for Twig + templates; however, starting with API v2 plugins might rely on `.twig` + as file extension, making this a BC-breaking change regardless +``` + +### Version 2.0.0-beta.1 +Released: 2017-11-05 + +**Note:** Pico's official `PicoDeprecated` plugin was moved to this separate + repository in preparation for Pico 2.0. Refer to Pico's changelog for + a list of changes to this plugin before Pico 2.0. + +``` +* [New] Update plugin to API v2 and add support for all API v1 events +* [New] Keep track of all loaded Pico plugins and distinguish them by the API + version they use; deprecated events are only triggered on plugins using + this particular API version (`PicoDeprecated::API_VERSION_*` constants) +* [New] Take care of triggering events on plugins using older API versions; + this includes not only core events, but also all custom events; as a + result, old plugin's always depend on `PicoDeprecated` now +* [New] Use a simple event alias table to keep track of unchanged or just + renamed core events +* [New] Add `rewrite_url` and `is_front_page` Twig variables +* [New] Add support for the `config/config.php` configuration file +* [New] Additionally compare registered meta headers case-insensitive +* [New] Make meta headers on the first level of a page's meta data also + available using a lowered key (as of Pico 1.0; i.e. `SomeKey: value` is + now accessible using both `$meta['SomeKey']` and `$meta['somekey']`) +* [New] Add public `PicoDeprecated::triggersApiEvents()` method +* [New] Add public `PicoDeprecated::triggerEvent()` method (and the additional + `$apiVersion` parameter) as replacement for the previously protected + method of the same name +* [Fixed] ! Don't overwrite the global `$config` variable if it is defined +* [Fixed] ! Improve re-indexing of pages added by the API v0 event `get_pages` +* [Changed] No longer try to guess whether the plugin needs to be enabled or + not, rather enable it by default (guessing was pretty error-prone) +* [Changed] ! Use a scope-isolated `require()` to include configuration files +* [Changed] ! Don't pass `$plugins` parameter to API v1 `onPluginsLoaded` event + by reference anymore; use `Pico::loadPlugin()` instead +* [Changed] ! The API v1 events `onTwigRegistration` and `onMetaHeaders`, as + well as the API v0 event `before_twig_register` are no longer part + of Pico's event flow and are triggered just once on demand +* [Changed] Improve PHP class docs +* [Changed] A vast number of small improvements and changes... +* [Removed] ! Remove support for `PicoParsePagesContent` plugin +* [Removed] ! Remove support for `PicoExcerpt` plugin +``` diff --git a/plugins/PicoDeprecated/LICENSE b/plugins/PicoDeprecated/LICENSE new file mode 100644 index 0000000..91a34cf --- /dev/null +++ b/plugins/PicoDeprecated/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2012 The Pico Community + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/plugins/PicoDeprecated/PicoDeprecated.php b/plugins/PicoDeprecated/PicoDeprecated.php new file mode 100644 index 0000000..9334661 --- /dev/null +++ b/plugins/PicoDeprecated/PicoDeprecated.php @@ -0,0 +1,383 @@ + + * + * The file was previously part of the project's main repository; the version + * control history of the original file applies accordingly, available from + * the following original location: + * + * + * + * SPDX-License-Identifier: MIT + * License-Filename: LICENSE + */ + +/** + * Maintain backward compatibility to older Pico releases + * + * `PicoDeprecated`'s purpose is to maintain backward compatibility to older + * versions of Pico, by re-introducing characteristics that were removed from + * Pico's core. + * + * `PicoDeprecated` is basically a mandatory plugin for all Pico installs. + * Without this plugin you can't use plugins which were written for other + * API versions than the one of Pico's core, even when there was just the + * slightest change. + * + * {@see http://picocms.org/plugins/deprecated/} for a full list of features. + * + * @author Daniel Rudolf + * @link http://picocms.org + * @license http://opensource.org/licenses/MIT The MIT License + * @version 2.1 + */ +class PicoDeprecated extends AbstractPicoPlugin +{ + /** + * API version used by this plugin + * + * @var int + */ + const API_VERSION = 3; + + /** + * API version 0, used by Pico 0.9 and earlier + * + * @var int + */ + const API_VERSION_0 = 0; + + /** + * API version 1, used by Pico 1.0 + * + * @var int + */ + const API_VERSION_1 = 1; + + /** + * API version 2, used by Pico 2.0 + * + * @var int + */ + const API_VERSION_2 = 2; + + /** + * API version 3, used by Pico 2.1 + * + * @var int + */ + const API_VERSION_3 = 3; + + /** + * Loaded plugins, indexed by API version + * + * @see PicoDeprecated::getPlugins() + * + * @var object[] + */ + protected $plugins = array(); + + /** + * Loaded compatibility plugins + * + * @see PicoDeprecated::getCompatPlugins() + * + * @var PicoCompatPluginInterface[] + */ + protected $compatPlugins = array(); + + /** + * {@inheritDoc} + */ + public function __construct(Pico $pico) + { + parent::__construct($pico); + + if (is_file(__DIR__ . '/vendor/autoload.php')) { + require(__DIR__ . '/vendor/autoload.php'); + } + + if (!class_exists('PicoMainCompatPlugin')) { + die( + "Cannot find PicoDeprecated's 'vendor/autoload.php'. If you're using a composer-based Pico install, " + . "run `composer update`. If you're rather trying to use one of PicoDeprecated's pre-built release " + . "packages, make sure to download PicoDeprecated's release package matching Pico's version named " + . "'pico-deprecated-release-v*.tar.gz' (don't download a source code package)." + ); + } + + if ($pico::API_VERSION !== static::API_VERSION) { + throw new RuntimeException( + 'PicoDeprecated requires API version ' . static::API_VERSION . ', ' + . 'but Pico is running API version ' . $pico::API_VERSION + ); + } + } + + /** + * {@inheritDoc} + */ + public function handleEvent($eventName, array $params) + { + parent::handleEvent($eventName, $params); + + // trigger events on compatibility plugins + if ($this->isEnabled() || ($eventName === 'onPluginsLoaded')) { + $isCoreEvent = in_array($eventName, $this->getCoreEvents()); + foreach ($this->compatPlugins as $plugin) { + if ($isCoreEvent) { + if ($plugin->getApiVersion() === static::API_VERSION) { + $plugin->handleEvent($eventName, $params); + } + } elseif ($plugin instanceof PicoPluginApiCompatPluginInterface) { + $plugin->handleCustomEvent($eventName, $params); + } + } + } + } + + /** + * Reads all loaded plugins and indexes them by API level, loads the + * necessary compatibility plugins + * + * @see PicoDeprecated::loadPlugin() + * + * @param object[] $plugins loaded plugin instances + */ + public function onPluginsLoaded(array $plugins) + { + $this->loadCompatPlugin('PicoMainCompatPlugin'); + + foreach ($plugins as $plugin) { + $this->loadPlugin($plugin); + } + + $this->getPico()->triggerEvent('onPicoDeprecated', array($this)); + } + + /** + * Adds a manually loaded plugin to PicoDeprecated's plugin index, loads + * the necessary compatibility plugins + * + * @see PicoDeprecated::loadPlugin() + * + * @param object $plugin loaded plugin instance + */ + public function onPluginManuallyLoaded($plugin) + { + $this->loadPlugin($plugin); + } + + /** + * Loads a compatibility plugin if Pico's theme uses a old theme API + * + * @param string $theme name of current theme + * @param int $themeApiVersion API version of the theme + * @param array $themeConfig config array of the theme + */ + public function onThemeLoaded($theme, $themeApiVersion, array &$themeConfig) + { + $this->loadThemeApiCompatPlugin($themeApiVersion); + } + + /** + * Adds a plugin to PicoDeprecated's plugin index + * + * @see PicoDeprecated::onPluginsLoaded() + * @see PicoDeprecated::onPluginManuallyLoaded() + * @see PicoDeprecated::getPlugins() + * + * @param object $plugin loaded plugin instance + */ + protected function loadPlugin($plugin) + { + $pluginName = get_class($plugin); + + $apiVersion = $this->getPluginApiVersion($plugin); + if (!isset($this->plugins[$apiVersion])) { + $this->plugins[$apiVersion] = array(); + $this->loadPluginApiCompatPlugin($apiVersion); + } + + $this->plugins[$apiVersion][$pluginName] = $plugin; + } + + /** + * Returns a list of all loaded Pico plugins using the given API level + * + * @param int $apiVersion API version to match plugins + * + * @return object[] loaded plugin instances + */ + public function getPlugins($apiVersion) + { + return isset($this->plugins[$apiVersion]) ? $this->plugins[$apiVersion] : array(); + } + + /** + * Loads a compatibility plugin + * + * @param PicoCompatPluginInterface|string $plugin either the class name of + * a plugin to instantiate or a plugin instance + * + * @return PicoCompatPluginInterface instance of the loaded plugin + */ + public function loadCompatPlugin($plugin) + { + if (!is_object($plugin)) { + $className = (string) $plugin; + if (class_exists($className)) { + $plugin = new $className($this->getPico(), $this); + } else { + throw new RuntimeException( + "Unable to load PicoDeprecated compatibility plugin '" . $className . "': Class not found" + ); + } + } + + $className = get_class($plugin); + if (isset($this->compatPlugins[$className])) { + return $this->compatPlugins[$className]; + } + + if (!($plugin instanceof PicoCompatPluginInterface)) { + throw new RuntimeException( + "Unable to load PicoDeprecated compatibility plugin '" . $className . "': " + . "Compatibility plugins must implement 'PicoCompatPluginInterface'" + ); + } + + $apiVersion = $plugin->getApiVersion(); + $this->loadPluginApiCompatPlugin($apiVersion); + + $dependsOn = $plugin->getDependencies(); + foreach ($dependsOn as $pluginDependency) { + $this->loadCompatPlugin($pluginDependency); + } + + $this->compatPlugins[$className] = $plugin; + + return $plugin; + } + + /** + * Loads a plugin API compatibility plugin + * + * @param int $apiVersion API version to load the compatibility plugin for + */ + protected function loadPluginApiCompatPlugin($apiVersion) + { + if ($apiVersion !== static::API_VERSION) { + $this->loadCompatPlugin('PicoPluginApi' . $apiVersion . 'CompatPlugin'); + } + } + + /** + * Loads a theme API compatibility plugin + * + * @param int $apiVersion API version to load the compatibility plugin for + */ + protected function loadThemeApiCompatPlugin($apiVersion) + { + if ($apiVersion !== static::API_VERSION) { + $this->loadCompatPlugin('PicoThemeApi' . $apiVersion . 'CompatPlugin'); + } + } + + /** + * Returns all loaded compatibility plugins + * + * @return PicoCompatPluginInterface[] list of loaded compatibility plugins + */ + public function getCompatPlugins() + { + return $this->compatPlugins; + } + + /** + * Triggers deprecated events on plugins of different API versions + * + * You can use this public method in other plugins to trigger custom events + * on plugins using a particular API version. If you want to trigger a + * custom event on all plugins, no matter their API version (except for + * plugins using API v0, which can't handle custom events), use + * {@see Pico::triggerEvent()} instead. + * + * @see Pico::triggerEvent() + * + * @param int $apiVersion API version of the event + * @param string $eventName event to trigger + * @param array $params optional parameters to pass + */ + public function triggerEvent($apiVersion, $eventName, array $params = array()) + { + foreach ($this->getPlugins($apiVersion) as $plugin) { + $plugin->handleEvent($eventName, $params); + } + } + + /** + * Returns the API version of a given plugin + * + * @param object $plugin plugin instance + * + * @return int API version used by the plugin + */ + public function getPluginApiVersion($plugin) + { + $pluginApiVersion = self::API_VERSION_0; + if ($plugin instanceof PicoPluginInterface) { + $pluginApiVersion = self::API_VERSION_1; + if (defined(get_class($plugin) . '::API_VERSION')) { + $pluginApiVersion = $plugin::API_VERSION; + } + } + + return $pluginApiVersion; + } + + /** + * Returns a list of the names of Pico's core events + * + * @return string[] list of Pico's core events + */ + public function getCoreEvents() + { + return array( + 'onPluginsLoaded', + 'onPluginManuallyLoaded', + 'onConfigLoaded', + 'onThemeLoading', + 'onThemeLoaded', + 'onRequestUrl', + 'onRequestFile', + 'onContentLoading', + 'on404ContentLoading', + 'on404ContentLoaded', + 'onContentLoaded', + 'onMetaParsing', + 'onMetaParsed', + 'onContentParsing', + 'onContentPrepared', + 'onContentParsed', + 'onPagesLoading', + 'onSinglePageLoading', + 'onSinglePageContent', + 'onSinglePageLoaded', + 'onPagesDiscovered', + 'onPagesLoaded', + 'onCurrentPageDiscovered', + 'onPageTreeBuilt', + 'onPageRendering', + 'onPageRendered', + 'onMetaHeaders', + 'onYamlParserRegistered', + 'onParsedownRegistered', + 'onTwigRegistered' + ); + } +} diff --git a/plugins/PicoDeprecated/README.md b/plugins/PicoDeprecated/README.md new file mode 100644 index 0000000..4c3091a --- /dev/null +++ b/plugins/PicoDeprecated/README.md @@ -0,0 +1,44 @@ +Pico Deprecated Plugin +====================== + +This is the repository of Pico's official `PicoDeprecated` plugin. + +Pico is a stupidly simple, blazing fast, flat file CMS. See http://picocms.org/ for more info. + +`PicoDeprecated`'s purpose is to maintain backward compatibility to older versions of Pico, by re-introducing characteristics that were removed from Pico's core. It for example triggers old events (like the `before_render` event used before Pico 1.0) and reads config files that were written in PHP (`config/config.php`, used before Pico 2.0). + +Please refer to [`picocms/Pico`](https://github.com/picocms/Pico) to get info about how to contribute or getting help. + +Install +------- + +You usually don't have to install this plugin manually, it's shipped together with [Pico's pre-built release packages](https://github.com/picocms/Pico/releases/latest) and a default dependency of [`picocms/pico-composer`](https://github.com/picocms/pico-composer). + +If you're using plugins and themes that are compatible with Pico's latest API version only, you can safely remove `PicoDeprecated` from your Pico installation or disable the plugin (please refer to the "Usage" section below). However, if you're not sure about this, simply leave it as it is - it won't hurt... :wink: + +If you use a `composer`-based installation of Pico and want to either remove or install `PicoDeprecated`, simply open a shell on your server and navigate to Pico's install directory (e.g. `/var/www/html`). Run `composer remove picocms/pico-deprecated` to remove `PicoDeprecated`, or run `composer require picocms/pico-deprecated` (via [Packagist.org](https://packagist.org/packages/picocms/pico-deprecated)) to install `PicoDeprecated`. + +If you rather use one of Pico's pre-built release packages, it is best to disable `PicoDeprecated` and not to actually remove it. The reason for this is, that `PicoDeprecated` is part of Pico's pre-built release packages, thus it will be automatically re-installed when updating Pico. However, if you really want to remove `PicoDeprecated`, simply delete the `plugins/PicoDeprecated` directory in Pico's install directory (e.g. `/var/www/html`). If you want to install `PicoDeprecated`, you must first create a empty `plugins/PicoDeprecated` directory on your server, [download the version of `PicoDeprecated`](https://github.com/picocms/pico-deprecated/releases) matching the version of your Pico installation and upload all containing files (esp. `PicoDeprecated.php` and the `lib/`, `plugins/` and `vendor/` directories) into said `plugins/PicoDeprecated` directory (resulting in `plugins/PicoDeprecated/PicoDeprecated.php`). + +The versioning of `PicoDeprecated` strictly follows the version of Pico's core. You *must not* use a version of `PicoDeprecated` that doesn't match the version of Pico's core (e.g. PicoDeprecated 2.0.1 is *not compatible* with Pico 2.0.0). If you're using a `composer`-based installation of Pico, simply use a version constaint like `^2.0` - `PicoDeprecated` ensures that its version matches Pico's version. Even if you're using one of Pico's pre-built release packages, you don't have to take care of anything - a matching version of `PicoDeprecated` is part of Pico's pre-built release packages anyway. + +Usage +----- + +You can explicitly disable `PicoDeprecated` by adding `PicoDeprecated.enabled: false` to your `config/config.yml`. If you want to re-enable `PicoDeprecated`, simply remove this line from your `config/config.yml`. `PicoDeprecated` itself has no configuration options, it enables and disables all of its features depending on whether there are plugins and/or themes requiring said characteristics. + +`PicoDeprecated`'s functionality is split into various so-called "compatibility plugins". There are compatibility plugins for every old API version (Pico 0.9 and earlier were using API version 0, Pico 1.0 was using API version 1 and Pico 2.0 was using API version 2; the current API version is version 3, used by Pico 2.1), one for plugins and another one for themes. Their purpose is to re-introduce characteristics plugins and themes using said API version might rely on. For example, plugin API compatibility plugins are responsible for simulating old Pico core events (like the `before_render` event used by Pico 0.9 and earlier). Theme API compatibility plugins will e.g. register old Twig variables (like the `is_front_page` Twig variable used by Pico 1.0). If you install a plugin using API version 2, the corresponding `PicoPluginApi2CompatPlugin` will be loaded. All plugin API compatibility plugins also depend on their theme counterpart, thus `PicoThemeApi2CompatPlugin` will be loaded, too. Furthermore all compatibility plugins depend on their respective API successors. + +The plugin exposes a simple API to allow other plugins to load their own compatibility plugins. As a plugin developer you may use the `PicoDeprecated::loadCompatPlugin(PicoCompatPluginInterface $compatPlugin)` method to load a custom compatibility plugin. Use `PicoDeprecated::getCompatPlugins()` to return a list of all loaded compatibility plugins. You can furthermore use the `PicoDeprecated::getPlugins(int $apiVersion)` method to return a list of all loaded Pico plugins using a particular API version. If you want to trigger a custom event on plugins using a particular API version only, use `PicoDeprecated::triggerEvent(int $apiVersion, string $eventName, array $parameters = [])`. `PicoDeprecated` furthermore triggers the custom `onPicoDeprecated(PicoDeprecated $picoDeprecated)` event. + +Getting Help +------------ + +Please refer to the ["Getting Help" section](https://github.com/picocms/Pico#getting-help) of our main repository. + +Contributing +------------ + +Please refer to the ["Contributing" section](https://github.com/picocms/Pico#contributing) of our main repository. + +By contributing to Pico, you accept and agree to the *Developer Certificate of Origin* for your present and future contributions submitted to Pico. Please refer to the ["Developer Certificate of Origin" section](https://github.com/picocms/Pico/blob/master/CONTRIBUTING.md#developer-certificate-of-origin) in the `CONTRIBUTING.md` of our main repository. diff --git a/plugins/PicoDeprecated/composer.json b/plugins/PicoDeprecated/composer.json new file mode 100644 index 0000000..daf56bc --- /dev/null +++ b/plugins/PicoDeprecated/composer.json @@ -0,0 +1,41 @@ +{ + "name": "picocms/pico-deprecated", + "type": "pico-plugin", + "description": "This is Pico's official PicoDeprecated plugin. Pico is a stupidly simple, blazing fast, flat file CMS.", + "keywords": [ "pico", "picocms", "picocms-plugin", "pico-deprecated", "compatibility", "deprecation" ], + "homepage": "http://picocms.org/", + "license": "MIT", + "authors": [ + { + "name": "Daniel Rudolf", + "email": "picocms.org@daniel-rudolf.de", + "role": "Lead Developer" + }, + { + "name": "The Pico Community", + "homepage": "http://picocms.org/" + }, + { + "name": "Contributors", + "homepage": "https://github.com/picocms/pico-deprecated/graphs/contributors" + } + ], + "support": { + "docs": "http://picocms.org/plugins/deprecated/", + "issues": "https://github.com/picocms/pico-deprecated/issues", + "source": "https://github.com/picocms/pico-deprecated" + }, + "require": { + "php": ">=5.3.0", + "picocms/pico": "self.version" + }, + "autoload": { + "classmap": [ "PicoDeprecated.php", "lib/", "plugins/" ] + }, + "extra": { + "branch-alias": { + "dev-master": "2.1.x-dev", + "dev-pico-3.0": "3.0.x-dev" + } + } +} diff --git a/plugins/PicoDeprecated/lib/AbstractPicoCompatPlugin.php b/plugins/PicoDeprecated/lib/AbstractPicoCompatPlugin.php new file mode 100644 index 0000000..1d3961a --- /dev/null +++ b/plugins/PicoDeprecated/lib/AbstractPicoCompatPlugin.php @@ -0,0 +1,101 @@ + + * + * SPDX-License-Identifier: MIT + * License-Filename: LICENSE + */ + +/** + * Abstract class to extend from when implementing a PicoDeprecated + * compatibility plugin + * + * Please refer to {@see PicoCompatPluginInterface} for more information about + * how to develop a PicoDeprecated compatibility plugin. + * + * @see PicoCompatPluginInterface + * + * @author Daniel Rudolf + * @link http://picocms.org + * @license http://opensource.org/licenses/MIT The MIT License + * @version 2.1 + */ +abstract class AbstractPicoCompatPlugin implements PicoCompatPluginInterface +{ + /** + * Current instance of Pico + * + * @see PicoCompatPluginInterface::getPico() + * + * @var Pico + */ + protected $pico; + + /** + * Instance of the main PicoDeprecated plugin + * + * @see PicoCompatPluginInterface::getPicoDeprecated() + * + * @var PicoDeprecated + */ + protected $picoDeprecated; + + /** + * List of plugins which this plugin depends on + * + * @see PicoCompatPluginInterface::getDependencies() + * + * @var string[] + */ + protected $dependsOn = array(); + + /** + * Constructs a new instance of a PicoDeprecated compatibility plugin + * + * @param Pico $pico current instance of Pico + * @param PicoDeprecated $picoDeprecated current instance of PicoDeprecated + */ + public function __construct(Pico $pico, PicoDeprecated $picoDeprecated) + { + $this->pico = $pico; + $this->picoDeprecated = $picoDeprecated; + } + + /** + * {@inheritDoc} + */ + public function handleEvent($eventName, array $params) + { + if (method_exists($this, $eventName)) { + call_user_func_array(array($this, $eventName), $params); + } + } + + /** + * {@inheritDoc} + */ + public function getPico() + { + return $this->pico; + } + + /** + * {@inheritDoc} + */ + public function getPicoDeprecated() + { + return $this->picoDeprecated; + } + + /** + * {@inheritDoc} + */ + public function getDependencies() + { + return (array) $this->dependsOn; + } +} diff --git a/plugins/PicoDeprecated/lib/AbstractPicoPluginApiCompatPlugin.php b/plugins/PicoDeprecated/lib/AbstractPicoPluginApiCompatPlugin.php new file mode 100644 index 0000000..af32b2f --- /dev/null +++ b/plugins/PicoDeprecated/lib/AbstractPicoPluginApiCompatPlugin.php @@ -0,0 +1,83 @@ + + * + * SPDX-License-Identifier: MIT + * License-Filename: LICENSE + */ + +/** + * Abstract class to extend from when implementing a PicoDeprecated plugin API + * compatibility plugin + * + * Please refer to {@see PicoPluginApiCompatPluginInterface} for more information about + * how to develop a PicoDeprecated plugin API compatibility plugin. + * + * @see PicoPluginApiCompatPluginInterface + * + * @author Daniel Rudolf + * @link http://picocms.org + * @license http://opensource.org/licenses/MIT The MIT License + * @version 2.1 + */ +abstract class AbstractPicoPluginApiCompatPlugin extends AbstractPicoCompatPlugin implements + PicoPluginApiCompatPluginInterface +{ + /** + * Map of core events matching event signatures of older API versions + * + * @see AbstractPicoPluginApiCompatPlugin::handleEvent() + * + * @var array + */ + protected $eventAliases = array(); + + /** + * {@inheritDoc} + */ + public function handleEvent($eventName, array $params) + { + parent::handleEvent($eventName, $params); + + // trigger core events matching the event signatures of older API versions + if (isset($this->eventAliases[$eventName])) { + foreach ($this->eventAliases[$eventName] as $eventAlias) { + $this->triggerEvent($eventAlias, $params); + } + } + } + + /** + * {@inheritDoc} + */ + public function handleCustomEvent($eventName, array $params = array()) + { + $this->getPicoDeprecated()->triggerEvent($this->getApiVersionSupport(), $eventName, $params); + } + + /** + * Triggers deprecated events on plugins of the supported API version + * + * @param string $eventName name of the event to trigger + * @param array $params optional parameters to pass + */ + protected function triggerEvent($eventName, array $params = array()) + { + $apiVersion = $this->getApiVersionSupport(); + $picoDeprecated = $this->getPicoDeprecated(); + + if ($apiVersion !== $picoDeprecated::API_VERSION) { + foreach ($picoDeprecated->getCompatPlugins() as $compatPlugin) { + if ($compatPlugin->getApiVersion() === $apiVersion) { + $compatPlugin->handleEvent($eventName, $params); + } + } + } + + $picoDeprecated->triggerEvent($apiVersion, $eventName, $params); + } +} diff --git a/plugins/PicoDeprecated/lib/PicoCompatPluginInterface.php b/plugins/PicoDeprecated/lib/PicoCompatPluginInterface.php new file mode 100644 index 0000000..6ede84f --- /dev/null +++ b/plugins/PicoDeprecated/lib/PicoCompatPluginInterface.php @@ -0,0 +1,62 @@ + + * + * SPDX-License-Identifier: MIT + * License-Filename: LICENSE + */ + +/** + * Common interface for PicoDeprecated compatibility plugins + * + * @author Daniel Rudolf + * @link http://picocms.org + * @license http://opensource.org/licenses/MIT The MIT License + * @version 2.1 + */ +interface PicoCompatPluginInterface +{ + /** + * Handles a Pico event + * + * @param string $eventName name of the triggered event + * @param array $params passed parameters + */ + public function handleEvent($eventName, array $params); + + /** + * Returns a list of names of compat plugins required by this plugin + * + * @return string[] required plugins + */ + public function getDependencies(); + + /** + * Returns the plugin's instance of Pico + * + * @see Pico + * + * @return Pico the plugin's instance of Pico + */ + public function getPico(); + + /** + * Returns the plugin's main PicoDeprecated plugin instance + * + * @see PicoDeprecated + * + * @return PicoDeprecated the plugin's instance of Pico + */ + public function getPicoDeprecated(); + + /** + * Returns the version of the API this plugin uses + * + * @return int the API version used by this plugin + */ + public function getApiVersion(); +} diff --git a/plugins/PicoDeprecated/lib/PicoPluginApiCompatPluginInterface.php b/plugins/PicoDeprecated/lib/PicoPluginApiCompatPluginInterface.php new file mode 100644 index 0000000..5e71768 --- /dev/null +++ b/plugins/PicoDeprecated/lib/PicoPluginApiCompatPluginInterface.php @@ -0,0 +1,37 @@ + + * + * SPDX-License-Identifier: MIT + * License-Filename: LICENSE + */ + +/** + * Common interface for PicoDeprecated plugin API compatibility plugins + * + * @author Daniel Rudolf + * @link http://picocms.org + * @license http://opensource.org/licenses/MIT The MIT License + * @version 2.1 + */ +interface PicoPluginApiCompatPluginInterface extends PicoCompatPluginInterface +{ + /** + * Handles custom events for plugins of the supported API version + * + * @param string $eventName name of the triggered event + * @param array $params passed parameters + */ + public function handleCustomEvent($eventName, array $params = array()); + + /** + * Returns the API version this plugin maintains backward compatibility for + * + * @return int + */ + public function getApiVersionSupport(); +} diff --git a/plugins/PicoDeprecated/plugins/PicoMainCompatPlugin.php b/plugins/PicoDeprecated/plugins/PicoMainCompatPlugin.php new file mode 100644 index 0000000..683aad9 --- /dev/null +++ b/plugins/PicoDeprecated/plugins/PicoMainCompatPlugin.php @@ -0,0 +1,102 @@ + + * + * This file was created by splitting up an original file into multiple files, + * which in turn was previously part of the project's main repository. The + * version control history of these files apply accordingly, available from + * the following original locations: + * + * + * + * + * SPDX-License-Identifier: MIT + * License-Filename: LICENSE + */ + +/** + * Maintains backward compatibility with older Pico versions + * + * @author Daniel Rudolf + * @link http://picocms.org + * @license http://opensource.org/licenses/MIT The MIT License + * @version 2.1 + */ +class PicoMainCompatPlugin extends AbstractPicoCompatPlugin +{ + /** + * Load's config.php from Pico's root and config dir + * + * Since we want to utilize Pico's own code dealing with particular config + * settings (like making paths and URLs absolute), we must call this before + * {@see Pico::loadConfig()}. `onConfigLoaded` is triggered later, thus we + * use the `onPluginsLoaded` event. + * + * @see PicoMainCompatPlugin::loadScriptedConfig() + * + * @param object[] $plugins loaded plugin instances + */ + public function onPluginsLoaded(array $plugins) + { + // deprecated since Pico 1.0 + if (is_file($this->getPico()->getRootDir() . 'config.php')) { + $this->loadScriptedConfig($this->getPico()->getRootDir() . 'config.php'); + } + + // deprecated since Pico 2.0 + if (is_file($this->getPico()->getConfigDir() . 'config.php')) { + $this->loadScriptedConfig($this->getPico()->getConfigDir() . 'config.php'); + } + } + + /** + * Reads a Pico PHP config file and injects the config into Pico + * + * This method injects the config into Pico using PHP's Reflection API + * (i.e. {@see ReflectionClass}). Even though the Reflection API was + * created to aid development and not to do things like this, it's the best + * solution. Otherwise we'd have to copy all of Pico's code dealing with + * special config settings (like making paths and URLs absolute). + * + * @see PicoMainCompatPlugin::onConfigLoaded() + * @see Pico::loadConfig() + * + * @param string $configFile path to the config file to load + */ + protected function loadScriptedConfig($configFile) + { + // scope isolated require() + $includeConfigClosure = function ($configFile) { + require($configFile); + return (isset($config) && is_array($config)) ? $config : array(); + }; + if (PHP_VERSION_ID >= 50400) { + $includeConfigClosure = $includeConfigClosure->bindTo(null); + } + + $scriptedConfig = $includeConfigClosure($configFile); + + if (!empty($scriptedConfig)) { + $picoReflector = new ReflectionObject($this->getPico()); + $picoConfigReflector = $picoReflector->getProperty('config'); + $picoConfigReflector->setAccessible(true); + + $config = $picoConfigReflector->getValue($this->getPico()) ?: array(); + $config += $scriptedConfig; + + $picoConfigReflector->setValue($this->getPico(), $config); + } + } + + /** + * {@inheritDoc} + */ + public function getApiVersion() + { + return PicoDeprecated::API_VERSION_3; + } +} diff --git a/plugins/PicoDeprecated/plugins/PicoPluginApi0CompatPlugin.php b/plugins/PicoDeprecated/plugins/PicoPluginApi0CompatPlugin.php new file mode 100644 index 0000000..d459524 --- /dev/null +++ b/plugins/PicoDeprecated/plugins/PicoPluginApi0CompatPlugin.php @@ -0,0 +1,314 @@ + + * + * This file was created by splitting up an original file into multiple files, + * which in turn was previously part of the project's main repository. The + * version control history of these files apply accordingly, available from + * the following original locations: + * + * + * + * + * SPDX-License-Identifier: MIT + * License-Filename: LICENSE + */ + +/** + * Maintains backward compatibility with plugins using API version 0, written + * for Pico 0.9 and earlier + * + * @author Daniel Rudolf + * @link http://picocms.org + * @license http://opensource.org/licenses/MIT The MIT License + * @version 2.1 + */ +class PicoPluginApi0CompatPlugin extends AbstractPicoPluginApiCompatPlugin +{ + /** + * This plugin extends {@see PicoPluginApi1CompatPlugin} and + * {@see PicoThemeApi0CompatPlugin} + * + * @var string[] + */ + protected $dependsOn = array('PicoPluginApi1CompatPlugin', 'PicoThemeApi0CompatPlugin'); + + /** + * Map of core events matching event signatures of older API versions + * + * @see AbstractPicoPluginApiCompatPlugin::handleEvent() + * + * @var array + */ + protected $eventAliases = array( + 'onConfigLoaded' => array('config_loaded'), + 'onRequestUrl' => array('request_url'), + 'onContentLoading' => array('before_load_content'), + 'on404ContentLoading' => array('before_404_load_content'), + 'onMetaParsed' => array('file_meta'), + 'onContentParsing' => array('before_parse_content'), + 'onContentParsed' => array('after_parse_content', 'content_parsed'), + 'onTwigRegistration' => array('before_twig_register'), + 'onPageRendered' => array('after_render') + ); + + /** + * Pico's request file + * + * @see Pico::$requestFile + * @see PicoPluginApi0CompatPlugin::onRequestFile() + * + * @var string|null + */ + protected $requestFile; + + /** + * Triggers the plugins_loaded event + * + * @param object[] $plugins loaded plugin instances + */ + public function onPluginsLoaded(array &$plugins) + { + $this->triggerEvent('plugins_loaded'); + } + + /** + * Defines various config-related constants and sets the $config global + * + * `ROOT_DIR`, `LIB_DIR`, `PLUGINS_DIR`, `THEMES_DIR`, `CONTENT_EXT` and + * `CACHE_DIR` were removed wih Pico 1.0, `CONTENT_DIR` existed just in + * Pico 0.9 and `CONFIG_DIR` existed just for a short time between Pico 0.9 + * and Pico 1.0. + * + * @param array &$config array of config variables + */ + public function onConfigLoaded(array &$config) + { + $this->defineConfigConstants($config); + + if (!isset($GLOBALS['config'])) { + $GLOBALS['config'] = &$config; + } + } + + /** + * Defines various config-related constants + * + * `ROOT_DIR`, `LIB_DIR`, `PLUGINS_DIR`, `THEMES_DIR`, `CONTENT_EXT` and + * `CACHE_DIR` were removed wih Pico 1.0, `CONTENT_DIR` existed just in + * Pico 0.9 and `CONFIG_DIR` existed just for a short time between Pico 0.9 + * and Pico 1.0. + * + * @param array &$config array of config variables + */ + protected function defineConfigConstants(array &$config) + { + if (!defined('ROOT_DIR')) { + define('ROOT_DIR', $this->getPico()->getRootDir()); + } + if (!defined('CONFIG_DIR')) { + define('CONFIG_DIR', $this->getPico()->getConfigDir()); + } + if (!defined('LIB_DIR')) { + $picoReflector = new ReflectionClass('Pico'); + define('LIB_DIR', dirname($picoReflector->getFileName()) . '/'); + } + if (!defined('PLUGINS_DIR')) { + define('PLUGINS_DIR', $this->getPico()->getPluginsDir()); + } + if (!defined('THEMES_DIR')) { + define('THEMES_DIR', $this->getPico()->getThemesDir()); + } + if (!defined('CONTENT_DIR')) { + define('CONTENT_DIR', $this->getPico()->getConfig('content_dir')); + } + if (!defined('CONTENT_EXT')) { + define('CONTENT_EXT', $this->getPico()->getConfig('content_ext')); + } + if (!defined('CACHE_DIR')) { + $twigConfig = $this->getPico()->getConfig('twig_config'); + define('CACHE_DIR', $twigConfig['cache'] ?: ''); + } + } + + /** + * Sets PicoPluginApi1CompatPlugin::$requestFile + * + * @see PicoPluginApi0CompatPlugin::$requestFile + * + * @param string &$file absolute path to the content file to serve + */ + public function onRequestFile(&$file) + { + $this->requestFile = &$file; + } + + /** + * Triggers the after_404_load_content event + * + * @param string &$rawContent raw file contents + */ + public function on404ContentLoaded(&$rawContent) + { + $this->triggerEvent('after_404_load_content', array(&$this->requestFile, &$rawContent)); + } + + /** + * Triggers the after_load_content event + * + * @param string &$rawContent raw file contents + */ + public function onContentLoaded(&$rawContent) + { + $this->triggerEvent('after_load_content', array(&$this->requestFile, &$rawContent)); + } + + /** + * Triggers the before_read_file_meta event + * + * @param string &$rawContent raw file contents + * @param string[] &$headers list of known meta header fields + */ + public function onMetaParsing(&$rawContent, array &$headers) + { + $this->triggerEvent('before_read_file_meta', array(&$headers)); + } + + /** + * Triggers the get_page_data event + * + * @param array &$pageData data of the loaded page + */ + public function onSinglePageLoaded(array &$pageData) + { + $this->triggerEvent('get_page_data', array(&$pageData, $pageData['meta'])); + } + + /** + * Triggers the get_pages event + * + * Please note that the `get_pages` event gets `$pages` passed without a + * array index. The index is rebuild later using either the `id` array key + * or is derived from the `url` array key. If it isn't possible to derive + * the array key, `~unknown` is being used. Duplicates are prevented by + * adding `~dup` when necessary. + * + * @param array[] &$pages sorted list of all known pages + * @param array|null &$currentPage data of the page being served + * @param array|null &$previousPage data of the previous page + * @param array|null &$nextPage data of the next page + */ + public function onPagesLoaded( + array &$pages, + array &$currentPage = null, + array &$previousPage = null, + array &$nextPage = null + ) { + // remove keys of pages array + $plainPages = array(); + foreach ($pages as &$plainPageData) { + $plainPages[] = &$plainPageData; + } + + // trigger event + $this->triggerEvent('get_pages', array(&$plainPages, &$currentPage, &$previousPage, &$nextPage)); + + // re-index pages array + $baseUrl = $this->getPico()->getBaseUrl(); + $baseUrlLength = strlen($baseUrl); + $urlRewritingEnabled = $this->getPico()->isUrlRewritingEnabled(); + + $pages = array(); + foreach ($plainPages as &$pageData) { + if (!isset($pageData['id'])) { + if (substr($pageData['url'], 0, $baseUrlLength) === $baseUrl) { + if ($urlRewritingEnabled && (substr($pageData['url'], $baseUrlLength, 1) === '?')) { + $pageData['id'] = substr($pageData['url'], $baseUrlLength + 1); + } else { + $pageData['id'] = substr($pageData['url'], $baseUrlLength); + } + } else { + // foreign URLs are indexed by ~unknown, ~unknown~dup1, ~unknown~dup2, … + $pageData['id'] = '~unknown'; + } + } + + // prevent duplicates + $id = $pageData['id']; + for ($i = 1; isset($pages[$id]); $i++) { + $id = $pageData['id'] . '~dup' . $i; + } + + $pages[$id] = &$pageData; + } + } + + /** + * Triggers the before_render event + * + * Please note that the `before_render` event gets `$templateName` passed + * without its file extension. The file extension is re-added later. + * + * @param Twig_Environment &$twig Twig instance + * @param string &$templateName file name of the template + * @param array &$twigVariables template variables + */ + public function onPageRendering(Twig_Environment &$twig, array &$twigVariables, &$templateName) + { + $templateNameInfo = pathinfo($templateName) + array('extension' => ''); + + // the template name hasn't had a file extension in API v0 + $templateName = $templateNameInfo['filename']; + + $this->triggerEvent('before_render', array(&$twigVariables, &$twig, &$templateName)); + + // recover original file extension + // we assume that all templates of a theme use the same file extension + $templateName = $templateName . '.' . $templateNameInfo['extension']; + } + + /** + * {@inheritDoc} + */ + public function handleCustomEvent($eventName, array $params = array()) + { + // never trigger custom events + } + + /** + * {@inheritDoc} + */ + public function triggerEvent($eventName, array $params = array()) + { + // we don't support compat plugins using API v0, so no need to take care of compat plugins here + // API v0 events are also triggered on plugins using API v1 (but not later) + $plugins = $this->getPicoDeprecated()->getPlugins(PicoDeprecated::API_VERSION_0); + $plugins += $this->getPicoDeprecated()->getPlugins(PicoDeprecated::API_VERSION_1); + + foreach ($plugins as $plugin) { + if (method_exists($plugin, $eventName)) { + call_user_func_array(array($plugin, $eventName), $params); + } + } + } + + /** + * {@inheritDoc} + */ + public function getApiVersion() + { + return PicoDeprecated::API_VERSION_1; + } + + /** + * {@inheritDoc} + */ + public function getApiVersionSupport() + { + return PicoDeprecated::API_VERSION_0; + } +} diff --git a/plugins/PicoDeprecated/plugins/PicoPluginApi1CompatPlugin.php b/plugins/PicoDeprecated/plugins/PicoPluginApi1CompatPlugin.php new file mode 100644 index 0000000..ea886df --- /dev/null +++ b/plugins/PicoDeprecated/plugins/PicoPluginApi1CompatPlugin.php @@ -0,0 +1,347 @@ + + * + * This file was created by splitting up an original file into multiple files, + * which in turn was previously part of the project's main repository. The + * version control history of these files apply accordingly, available from + * the following original locations: + * + * + * + * + * SPDX-License-Identifier: MIT + * License-Filename: LICENSE + */ + +/** + * Maintains backward compatibility with plugins using API version 1, written + * for Pico 1.0 + * + * @author Daniel Rudolf + * @link http://picocms.org + * @license http://opensource.org/licenses/MIT The MIT License + * @version 2.1 + */ +class PicoPluginApi1CompatPlugin extends AbstractPicoPluginApiCompatPlugin +{ + /** + * This plugin extends {@see PicoPluginApi2CompatPlugin} and + * {@see PicoThemeApi1CompatPlugin} + * + * @var string[] + */ + protected $dependsOn = array('PicoPluginApi2CompatPlugin', 'PicoThemeApi1CompatPlugin'); + + /** + * Map of core events matching event signatures of older API versions + * + * @see AbstractPicoPluginApiCompatPlugin::handleEvent() + * + * @var array + */ + protected $eventAliases = array( + 'onConfigLoaded' => array('onConfigLoaded'), + 'onRequestUrl' => array('onRequestUrl'), + 'onRequestFile' => array('onRequestFile'), + 'on404ContentLoaded' => array('on404ContentLoaded'), + 'onContentLoaded' => array('onContentLoaded'), + 'onContentPrepared' => array('onContentPrepared'), + 'onContentParsed' => array('onContentParsed'), + 'onPagesLoading' => array('onPagesLoading'), + 'onSinglePageLoaded' => array('onSinglePageLoaded'), + 'onPageRendered' => array('onPageRendered') + ); + + /** + * Pico's request file + * + * @see Pico::$requestFile + * @see PicoPluginApi1CompatPlugin::onRequestFile() + * + * @var string|null + */ + protected $requestFile; + + /** + * Pico's raw contents + * + * @see Pico::$rawContent + * @see PicoPluginApi1CompatPlugin::onContentLoaded() + * + * @var string|null + */ + protected $rawContent; + + /** + * Pico's meta headers array + * + * @see Pico::$metaHeaders + * @see PicoPluginApi1CompatPlugin::onMetaHeaders() + * + * @var array|null + */ + protected $metaHeaders; + + /** + * Pico's pages array + * + * @see Pico::$pages + * @see PicoPluginApi1CompatPlugin::onPagesLoaded() + * + * @var array[]|null + */ + protected $pages; + + /** + * Pico's Twig instance + * + * @see Pico::$twig + * @see PicoPluginApi1CompatPlugin::onTwigRegistered() + * + * @var Twig_Environment|null + */ + protected $twig; + + /** + * Triggers the onPluginsLoaded event + * + * Prior to API v2 the event `onPluginsLoaded` passed the `$plugins` array + * by reference. This is no longer the case. We still pass the parameter by + * reference and use {@see Pico::loadPlugin()} to load additional plugins, + * however, unloading or replacing plugins was removed without a + * replacement. This might be a BC-breaking change for you! + * + * @param object[] $plugins loaded plugin instances + */ + public function onPluginsLoaded(array $plugins) + { + $originalPlugins = $plugins; + + $this->triggerEvent('onPluginsLoaded', array(&$plugins)); + + foreach ($plugins as $pluginName => $plugin) { + if (!isset($originalPlugins[$pluginName])) { + $this->getPico()->loadPlugin($plugin); + } elseif ($plugin !== $originalPlugins[$pluginName]) { + throw new RuntimeException( + "A Pico plugin using API version 1 tried to replace Pico plugin '" . $pluginName . "' using the " + . "onPluginsLoaded() event, however, replacing plugins was removed with API version 2" + ); + } + + unset($originalPlugins[$pluginName]); + } + + if ($originalPlugins) { + $removedPluginsList = implode("', '", array_keys($originalPlugins)); + throw new RuntimeException( + "A Pico plugin using API version 1 tried to unload the Pico plugin(s) '" . $removedPluginsList . "' " + . "using the onPluginsLoaded() event, however, unloading plugins was removed with API version 2" + ); + } + } + + /** + * Sets PicoPluginApi1CompatPlugin::$requestFile + * + * @see PicoPluginApi1CompatPlugin::$requestFile + * + * @param string &$file absolute path to the content file to serve + */ + public function onRequestFile(&$file) + { + $this->requestFile = &$file; + } + + /** + * Triggers the onContentLoading event + */ + public function onContentLoading() + { + $this->triggerEvent('onContentLoading', array(&$this->requestFile)); + } + + /** + * Sets PicoPluginApi1CompatPlugin::$rawContent + * + * @see PicoPluginApi1CompatPlugin::$rawContent + * + * @param string &$rawContent raw file contents + */ + public function onContentLoaded(&$rawContent) + { + $this->rawContent = &$rawContent; + } + + /** + * Triggers the on404ContentLoading event + */ + public function on404ContentLoading() + { + $this->triggerEvent('on404ContentLoading', array(&$this->requestFile)); + } + + /** + * Triggers the onMetaParsing event + * + * @see PicoPluginApi1CompatPlugin::onMetaHeaders() + */ + public function onMetaParsing() + { + $headersFlipped = $this->getFlippedMetaHeaders(); + $this->triggerEvent('onMetaParsing', array(&$this->rawContent, &$headersFlipped)); + $this->updateFlippedMetaHeaders($headersFlipped); + } + + /** + * Triggers the onMetaParsed and onParsedownRegistration events + * + * @param string[] &$meta parsed meta data + */ + public function onMetaParsed(array &$meta) + { + $this->triggerEvent('onMetaParsed', array(&$meta)); + $this->triggerEvent('onParsedownRegistration'); + } + + /** + * Triggers the onContentParsing event + */ + public function onContentParsing() + { + $this->triggerEvent('onContentParsing', array(&$this->rawContent)); + } + + /** + * Sets PicoPluginApi1CompatPlugin::$pages + * + * @see PicoPluginApi1CompatPlugin::$pages + * + * @param array[] &$pages sorted list of all known pages + */ + public function onPagesLoaded(array &$pages) + { + $this->pages = &$pages; + } + + /** + * Triggers the onPagesLoaded and onTwigRegistration events + * + * @param array|null &$currentPage data of the page being served + * @param array|null &$previousPage data of the previous page + * @param array|null &$nextPage data of the next page + */ + public function onCurrentPageDiscovered( + array &$currentPage = null, + array &$previousPage = null, + array &$nextPage = null + ) { + $this->triggerEvent('onPagesLoaded', array(&$this->pages, &$currentPage, &$previousPage, &$nextPage)); + + $this->triggerEvent('onTwigRegistration'); + $this->getPico()->getTwig(); + } + + /** + * Triggers the onPageRendering event + * + * @param string &$templateName file name of the template + * @param array &$twigVariables template variables + */ + public function onPageRendering(&$templateName, array &$twigVariables) + { + $this->triggerEvent('onPageRendering', array(&$this->twig, &$twigVariables, &$templateName)); + } + + /** + * Triggers the onMetaHeaders event with flipped meta headers and sets + * PicoPluginApi1CompatPlugin::$metaHeaders + * + * @see PicoPluginApi1CompatPlugin::$metaHeaders + * + * @param string[] &$headers list of known meta header fields; the array + * key specifies the YAML key to search for, the array value is later + * used to access the found value + */ + public function onMetaHeaders(array &$headers) + { + $this->metaHeaders = &$headers; + + $headersFlipped = $this->getFlippedMetaHeaders(); + $this->triggerEvent('onMetaHeaders', array(&$headersFlipped)); + $this->updateFlippedMetaHeaders($headersFlipped); + } + + /** + * Sets PicoPluginApi1CompatPlugin::$twig + * + * @see PicoPluginApi1CompatPlugin::$twig + * + * @param Twig_Environment &$twig Twig instance + */ + public function onTwigRegistered(Twig_Environment &$twig) + { + $this->twig = $twig; + } + + /** + * Returns the flipped meta headers array + * + * Pico 1.0 and earlier were using the values of the meta headers array to + * match registered meta headers in a page's meta data, and used the keys + * of the meta headers array to store the meta value in the page's meta + * data. However, starting with Pico 2.0 it is the other way round. This + * allows us to specify multiple "search strings" for a single registered + * meta value (e.g. "Nyan Cat" and "Tac Nayn" can be synonmous). + * + * @return array flipped meta headers + */ + protected function getFlippedMetaHeaders() + { + if ($this->metaHeaders === null) { + // make sure to trigger the onMetaHeaders event + $this->getPico()->getMetaHeaders(); + } + + return array_flip($this->metaHeaders ?: array()); + } + + /** + * Syncs PicoPluginApi1CompatPlugin::$metaHeaders with a flipped headers array + * + * @param array $headersFlipped flipped headers array + */ + protected function updateFlippedMetaHeaders(array $headersFlipped) + { + foreach ($this->metaHeaders as $name => $key) { + if (!isset($headersFlipped[$key])) { + unset($this->metaHeaders[$name]); + } + } + + foreach ($headersFlipped as $key => $name) { + $this->metaHeaders[$name] = $key; + } + } + + /** + * {@inheritDoc} + */ + public function getApiVersion() + { + return PicoDeprecated::API_VERSION_2; + } + + /** + * {@inheritDoc} + */ + public function getApiVersionSupport() + { + return PicoDeprecated::API_VERSION_1; + } +} diff --git a/plugins/PicoDeprecated/plugins/PicoPluginApi2CompatPlugin.php b/plugins/PicoDeprecated/plugins/PicoPluginApi2CompatPlugin.php new file mode 100644 index 0000000..a9ebbee --- /dev/null +++ b/plugins/PicoDeprecated/plugins/PicoPluginApi2CompatPlugin.php @@ -0,0 +1,131 @@ + + * + * This file was created by splitting up an original file into multiple files, + * which in turn was previously part of the project's main repository. The + * version control history of these files apply accordingly, available from + * the following original locations: + * + * + * + * + * SPDX-License-Identifier: MIT + * License-Filename: LICENSE + */ + +/** + * Maintains backward compatibility with plugins using API version 2, written + * for Pico 2.0 + * + * @author Daniel Rudolf + * @link http://picocms.org + * @license http://opensource.org/licenses/MIT The MIT License + * @version 2.1 + */ +class PicoPluginApi2CompatPlugin extends AbstractPicoPluginApiCompatPlugin +{ + /** + * This plugin extends {@see PicoThemeApi2CompatPlugin} + * + * @var string[] + */ + protected $dependsOn = array('PicoThemeApi2CompatPlugin'); + + /** + * Map of core events matching event signatures of older API versions + * + * @see AbstractPicoPluginApiCompatPlugin::handleEvent() + * + * @var array + */ + protected $eventAliases = array( + 'onPluginsLoaded' => array('onPluginsLoaded'), + 'onPluginManuallyLoaded' => array('onPluginManuallyLoaded'), + 'onRequestUrl' => array('onRequestUrl'), + 'onRequestFile' => array('onRequestFile'), + 'onContentLoading' => array('onContentLoading'), + 'on404ContentLoading' => array('on404ContentLoading'), + 'on404ContentLoaded' => array('on404ContentLoaded'), + 'onContentLoaded' => array('onContentLoaded'), + 'onMetaParsing' => array('onMetaParsing'), + 'onMetaParsed' => array('onMetaParsed'), + 'onContentParsing' => array('onContentParsing'), + 'onContentPrepared' => array('onContentPrepared'), + 'onContentParsed' => array('onContentParsed'), + 'onPagesLoading' => array('onPagesLoading'), + 'onSinglePageLoading' => array('onSinglePageLoading'), + 'onSinglePageContent' => array('onSinglePageContent'), + 'onSinglePageLoaded' => array('onSinglePageLoaded'), + 'onPagesDiscovered' => array('onPagesDiscovered'), + 'onPagesLoaded' => array('onPagesLoaded'), + 'onCurrentPageDiscovered' => array('onCurrentPageDiscovered'), + 'onPageTreeBuilt' => array('onPageTreeBuilt'), + 'onPageRendering' => array('onPageRendering'), + 'onPageRendered' => array('onPageRendered'), + 'onMetaHeaders' => array('onMetaHeaders'), + 'onYamlParserRegistered' => array('onYamlParserRegistered'), + 'onParsedownRegistered' => array('onParsedownRegistered'), + 'onTwigRegistered' => array('onTwigRegistered') + ); + + /** + * Pico's config array + * + * @see Pico::$config + * @see PicoPluginApi2CompatPlugin::onConfigLoaded() + * + * @var array|null + */ + protected $config; + + /** + * Sets PicoPluginApi1CompatPlugin::$config and handles the theme_url + * config param + * + * @see PicoPluginApi2CompatPlugin::$config + * + * @param array $config + */ + public function onConfigLoaded(array &$config) + { + $this->config = &$config; + + if (!empty($config['theme_url'])) { + $config['themes_url'] = $this->getPico()->getAbsoluteUrl($config['theme_url']); + $config['theme_url'] = &$config['themes_url']; + } + } + + /** + * Triggers the onConfigLoaded event + * + * @param string $theme name of current theme + * @param int $themeApiVersion API version of the theme + * @param array &$themeConfig config array of the theme + */ + public function onThemeLoaded($theme, $themeApiVersion, array &$themeConfig) + { + $this->triggerEvent('onConfigLoaded', array(&$this->config)); + } + + /** + * {@inheritDoc} + */ + public function getApiVersion() + { + return PicoDeprecated::API_VERSION_3; + } + + /** + * {@inheritDoc} + */ + public function getApiVersionSupport() + { + return PicoDeprecated::API_VERSION_2; + } +} diff --git a/plugins/PicoDeprecated/plugins/PicoThemeApi0CompatPlugin.php b/plugins/PicoDeprecated/plugins/PicoThemeApi0CompatPlugin.php new file mode 100644 index 0000000..9ed6a64 --- /dev/null +++ b/plugins/PicoDeprecated/plugins/PicoThemeApi0CompatPlugin.php @@ -0,0 +1,52 @@ + + * + * This file was created by splitting up an original file into multiple files, + * which in turn was previously part of the project's main repository. The + * version control history of these files apply accordingly, available from + * the following original locations: + * + * + * + * + * SPDX-License-Identifier: MIT + * License-Filename: LICENSE + */ + +/** + * Maintains backward compatibility with themes using API version 0, written + * for Pico 0.9 and earlier + * + * Since there were no theme-related changes between Pico 0.9 and Pico 1.0, + * this compat plugin doesn't hold any code itself, it just depends on + * {@see PicoThemeApi1CompatPlugin}. Since themes didn't support API versioning + * until Pico 2.1 (i.e. API version 3), all older themes will appear to use API + * version 0. + * + * @author Daniel Rudolf + * @link http://picocms.org + * @license http://opensource.org/licenses/MIT The MIT License + * @version 2.1 + */ +class PicoThemeApi0CompatPlugin extends AbstractPicoCompatPlugin +{ + /** + * This plugin extends {@see PicoThemeApi1CompatPlugin} + * + * @var string[] + */ + protected $dependsOn = array('PicoThemeApi1CompatPlugin'); + + /** + * {@inheritDoc} + */ + public function getApiVersion() + { + return PicoDeprecated::API_VERSION_3; + } +} diff --git a/plugins/PicoDeprecated/plugins/PicoThemeApi1CompatPlugin.php b/plugins/PicoDeprecated/plugins/PicoThemeApi1CompatPlugin.php new file mode 100644 index 0000000..f4b276b --- /dev/null +++ b/plugins/PicoDeprecated/plugins/PicoThemeApi1CompatPlugin.php @@ -0,0 +1,154 @@ + + * + * This file was created by splitting up an original file into multiple files, + * which in turn was previously part of the project's main repository. The + * version control history of these files apply accordingly, available from + * the following original locations: + * + * + * + * + * SPDX-License-Identifier: MIT + * License-Filename: LICENSE + */ + +/** + * Maintains backward compatibility with themes using API version 1, written + * for Pico 1.0 + * + * @author Daniel Rudolf + * @link http://picocms.org + * @license http://opensource.org/licenses/MIT The MIT License + * @version 2.1 + */ +class PicoThemeApi1CompatPlugin extends AbstractPicoCompatPlugin +{ + /** + * This plugin extends {@see PicoThemeApi2CompatPlugin} + * + * @var string[] + */ + protected $dependsOn = array('PicoThemeApi2CompatPlugin'); + + /** + * Lowers the page's meta headers + * + * @see PicoThemeApi1CompatPlugin::lowerFileMeta() + * + * @param string[] &$meta parsed meta data + */ + public function onMetaParsed(array &$meta) + { + $this->lowerFileMeta($meta); + } + + /** + * Lowers the page's meta headers + * + * @see PicoThemeApi1CompatPlugin::lowerFileMeta() + * + * @param array &$pageData data of the loaded page + */ + public function onSinglePageLoaded(array &$pageData) + { + // don't lower the file meta of the requested page, + // it was already lowered during the onMetaParsed event + $contentDir = $this->getPico()->getConfig('content_dir'); + $contentExt = $this->getPico()->getConfig('content_ext'); + if ($contentDir . $pageData['id'] . $contentExt !== $this->getPico()->getRequestFile()) { + $this->lowerFileMeta($pageData['meta']); + } + } + + /** + * Handles .html Twig templates and re-introcudes the Twig variables + * rewrite_url and is_front_page + * + * @param string &$templateName file name of the template + * @param array &$twigVariables template variables + */ + public function onPageRendering(&$templateName, array &$twigVariables) + { + if (!isset($twigVariables['rewrite_url'])) { + $twigVariables['rewrite_url'] = $this->getPico()->isUrlRewritingEnabled(); + } + + if (!isset($twigVariables['is_front_page'])) { + $contentDir = $this->getPico()->getConfig('content_dir'); + $contentExt = $this->getPico()->getConfig('content_ext'); + $requestFile = $this->getPico()->getRequestFile(); + $twigVariables['is_front_page'] = ($requestFile === $contentDir . 'index' . $contentExt); + } + + // API v2 requires themes to use .twig as file extension + // try to load the template and if this fails, try .html instead (as of API v1) + $templateNameInfo = pathinfo($templateName) + array('extension' => ''); + $twig = $this->getPico()->getTwig(); + + try { + $twig->loadTemplate($templateName); + } catch (Twig_Error_Loader $e) { + if ($templateNameInfo['extension'] === 'twig') { + try { + $twig->loadTemplate($templateNameInfo['filename'] . '.html'); + + $templateName = $templateNameInfo['filename'] . '.html'; + $templateNameInfo['extension'] = 'html'; + } catch (Twig_Error_Loader $e) { + // template doesn't exist, Twig will very likely fail later + } + } + } + } + + /** + * Lowers a page's meta headers as with Pico 1.0 and older + * + * This makes unregistered meta headers available using lowered array keys + * and matches registered meta headers in a case-insensitive manner. + * + * @param array &$meta meta data + */ + protected function lowerFileMeta(array &$meta) + { + $metaHeaders = $this->getPico()->getMetaHeaders(); + + // get unregistered meta + $unregisteredMeta = array(); + foreach ($meta as $key => $value) { + if (!in_array($key, $metaHeaders)) { + $unregisteredMeta[$key] = &$meta[$key]; + } + } + + // Pico 1.0 lowered unregistered meta unsolicited... + if ($unregisteredMeta) { + $metaHeadersLowered = array_change_key_case($metaHeaders, CASE_LOWER); + foreach ($unregisteredMeta as $key => $value) { + $keyLowered = strtolower($key); + if (isset($metaHeadersLowered[$keyLowered])) { + $registeredKey = $metaHeadersLowered[$keyLowered]; + if ($meta[$registeredKey] === '') { + $meta[$registeredKey] = &$unregisteredMeta[$key]; + } + } elseif (!isset($meta[$keyLowered]) || ($meta[$keyLowered] === '')) { + $meta[$keyLowered] = &$unregisteredMeta[$key]; + } + } + } + } + + /** + * {@inheritDoc} + */ + public function getApiVersion() + { + return PicoDeprecated::API_VERSION_3; + } +} diff --git a/plugins/PicoDeprecated/plugins/PicoThemeApi2CompatPlugin.php b/plugins/PicoDeprecated/plugins/PicoThemeApi2CompatPlugin.php new file mode 100644 index 0000000..646925b --- /dev/null +++ b/plugins/PicoDeprecated/plugins/PicoThemeApi2CompatPlugin.php @@ -0,0 +1,205 @@ + + * + * This file was created by splitting up an original file into multiple files, + * which in turn was previously part of the project's main repository. The + * version control history of these files apply accordingly, available from + * the following original locations: + * + * + * + * + * SPDX-License-Identifier: MIT + * License-Filename: LICENSE + */ + +/** + * Maintains backward compatibility with themes using API version 2, written + * for Pico 2.0 + * + * @author Daniel Rudolf + * @link http://picocms.org + * @license http://opensource.org/licenses/MIT The MIT License + * @version 2.1 + */ +class PicoThemeApi2CompatPlugin extends AbstractPicoCompatPlugin +{ + /** + * Manually configured Twig escape strategy + * + * @var mixed|null + */ + protected $twigEscapeStrategy; + + /** + * Directory paths of plugins + * + * @var string[] + */ + protected $pluginPaths = array(); + + /** + * Sets PicoThemeApi2CompatPlugin::$twigEscapeStrategy + * + * @see PicoThemeApi2CompatPlugin::$twigEscapeStrategy + * + * @param array &$config array of config variables + */ + public function onConfigLoaded(array &$config) + { + if (isset($config['twig_config']['autoescape'])) { + $this->twigEscapeStrategy = $config['twig_config']['autoescape']; + } + } + + /** + * Re-introduces the Twig variables prev_page, base_dir and theme_dir + * + * @param string &$templateName file name of the template + * @param array &$twigVariables template variables + */ + public function onPageRendering(&$templateName, array &$twigVariables) + { + $twigVariables['prev_page'] = &$twigVariables['previous_page']; + $twigVariables['base_dir'] = rtrim($this->getPico()->getRootDir(), '/'); + $twigVariables['theme_dir'] = $this->getPico()->getThemesDir() . $this->getPico()->getTheme(); + } + + /** + * Registers PicoPluginApi2CompatPlugin::twigEscapeStrategy() as Twig's + * default escape strategy + * + * @see PicoPluginApi2CompatPlugin::twigEscapeStrategy() + * + * @param Twig_Environment &$twig Twig instance + */ + public function onTwigRegistered(Twig_Environment &$twig) + { + if ($twig->hasExtension('Twig_Extension_Escaper')) { + /** @var Twig_Extension_Escaper $escaperExtension */ + $escaperExtension = $twig->getExtension('Twig_Extension_Escaper'); + $escaperExtension->setDefaultStrategy(array($this, 'twigEscapeStrategy')); + } + } + + /** + * Returns Twig's default escaping strategy for the given template + * + * This escape strategy takes a template name and decides whether Twig's + * global default escape strategy should be used, or escaping should be + * disabled. Escaping is disabled for themes using API v2 and below as well + * as for templates of plugins using API v2 and below. If a escape strategy + * has been configured manually, this method always returns this explicitly + * configured escape strategy. + * + * @param string $templateName template name + * + * @return string|false escape strategy for this template + */ + public function twigEscapeStrategy($templateName) + { + $twigConfig = $this->getPico()->getConfig('twig_config'); + $escapeStrategy = $twigConfig['autoescape']; + + if (($this->twigEscapeStrategy !== null) && ($escapeStrategy === $this->twigEscapeStrategy)) { + return $escapeStrategy; + } + + if (!is_string($escapeStrategy) && ($escapeStrategy !== false)) { + $escapeStrategy = call_user_func($escapeStrategy, $templateName); + } + + if ($escapeStrategy === false) { + return false; + } + + /** @var Twig_SourceContextLoaderInterface $twigLoader */ + $twigLoader = $this->getPico()->getTwig()->getLoader(); + if (!$twigLoader instanceof Twig_SourceContextLoaderInterface) { + throw new RuntimeException( + "PicoDeprecated compat plugin '" . __CLASS__ . "' requires a 'Twig_SourceContextLoaderInterface' " + . "Twig loader, '" . get_class($twigLoader) . "' given" + ); + } + + try { + $templatePath = $twigLoader->getSourceContext($templateName)->getPath(); + } catch (\Twig\Error\LoaderError $e) { + $templatePath = ''; + } + + if ($templatePath) { + $themePath = realpath($this->getPico()->getThemesDir() . $this->getPico()->getTheme()) . '/'; + if (substr($templatePath, 0, strlen($themePath)) === $themePath) { + $themeApiVersion = $this->getPico()->getThemeApiVersion(); + return ($themeApiVersion >= PicoDeprecated::API_VERSION_3) ? $escapeStrategy : false; + } + + $plugin = $this->getPluginFromPath($templatePath); + if ($plugin) { + $pluginApiVersion = $this->getPicoDeprecated()->getPluginApiVersion($plugin); + return ($pluginApiVersion >= PicoDeprecated::API_VERSION_3) ? $escapeStrategy : false; + } + } + + // unknown template path + // to preserve BC we must assume that the template uses an old API version + return false; + } + + /** + * Returns the matching plugin instance when the given path is within a + * plugin's base directory + * + * @param string $path file path to search for + * + * @return object|null either the matching plugin instance or NULL + */ + protected function getPluginFromPath($path) + { + $plugins = $this->getPico()->getPlugins(); + foreach ($this->pluginPaths as $pluginName => $pluginPath) { + if ($pluginPath && (substr($path, 0, strlen($pluginPath)) === $pluginPath)) { + return $plugins[$pluginName]; + } + } + + $rootDir = realpath($this->getPico()->getRootDir()) . '/'; + $vendorDir = realpath($this->getPico()->getVendorDir()) . '/'; + $pluginsDir = realpath($this->getPico()->getPluginsDir()) . '/'; + $themesDir = realpath($this->getPico()->getThemesDir()) . '/'; + foreach ($plugins as $pluginName => $plugin) { + if (isset($this->pluginPaths[$pluginName])) { + continue; + } + + $pluginReflector = new ReflectionObject($plugin); + + $pluginPath = dirname($pluginReflector->getFileName() ?: '') . '/'; + if (in_array($pluginPath, array('/', $rootDir, $vendorDir, $pluginsDir, $themesDir), true)) { + $pluginPath = ''; + } + + $this->pluginPaths[$pluginName] = $pluginPath; + + if ($pluginPath && (substr($path, 0, strlen($pluginPath)) === $pluginPath)) { + return $plugins[$pluginName]; + } + } + + return null; + } + + /** + * {@inheritDoc} + */ + public function getApiVersion() + { + return PicoDeprecated::API_VERSION_3; + } +} diff --git a/vendor/erusev/parsedown-extra/.gitignore b/vendor/erusev/parsedown-extra/.gitignore deleted file mode 100644 index d1502b0..0000000 --- a/vendor/erusev/parsedown-extra/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -vendor/ -composer.lock diff --git a/vendor/picocms/composer-installer/.gitignore b/vendor/picocms/composer-installer/.gitignore deleted file mode 100644 index 768fc06..0000000 --- a/vendor/picocms/composer-installer/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -# Linux -*~ -*.swp - -# Windows -Thumbs.db -desktop.ini - -# Mac OS X -.DS_Store -._* - -# Composer -/composer.lock -/composer.phar -/vendor diff --git a/vendor/symfony/yaml/.gitignore b/vendor/symfony/yaml/.gitignore deleted file mode 100644 index c49a5d8..0000000 --- a/vendor/symfony/yaml/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -vendor/ -composer.lock -phpunit.xml diff --git a/vendor/twig/twig/.gitignore b/vendor/twig/twig/.gitignore deleted file mode 100644 index 3110362..0000000 --- a/vendor/twig/twig/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -/build -/composer.lock -/ext/twig/autom4te.cache/ -/phpunit.xml -/vendor diff --git a/vendor/twig/twig/ext/twig/.gitignore b/vendor/twig/twig/ext/twig/.gitignore deleted file mode 100644 index 56ea76c..0000000 --- a/vendor/twig/twig/ext/twig/.gitignore +++ /dev/null @@ -1,30 +0,0 @@ -*.sw* -.deps -Makefile -Makefile.fragments -Makefile.global -Makefile.objects -acinclude.m4 -aclocal.m4 -build/ -config.cache -config.guess -config.h -config.h.in -config.log -config.nice -config.status -config.sub -configure -configure.in -install-sh -libtool -ltmain.sh -missing -mkinstalldirs -run-tests.php -twig.loT -.libs/ -modules/ -twig.la -twig.lo