diff --git a/.gitignore b/.gitignore index 792139f..0ea8ea8 100644 --- a/.gitignore +++ b/.gitignore @@ -4,8 +4,5 @@ cache/lastSitemap.txt cache/lastCache.txt settings/settings.yaml plugins -typemill.zip -typemill-1.0.1.zip -typemill-1.0.2.zip -typemill-1.0.3.zip +zips zip.php \ No newline at end of file diff --git a/composer.json b/composer.json index 39c642d..6cf8533 100644 --- a/composer.json +++ b/composer.json @@ -14,13 +14,15 @@ "slim/twig-view": "~2.3", "slim/flash": "~0.4", "symfony/yaml": "~2.8", + "symfony/event-dispatcher": "~3.3", "erusev/parsedown": "~1.4", "erusev/parsedown-extra": "dev-master", "jbroadway/urlify": "~1.1" }, "autoload": { "psr-4": { - "Typemill\\": "system" + "Typemill\\": "system", + "Plugins\\": "plugins" } } } \ No newline at end of file diff --git a/composer.lock b/composer.lock index 48a0a8b..0402273 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "d5756d6121a1cf74d8c17d9ba55ae0d5", + "content-hash": "f4e4110212e9000bba2745d405bae5b2", "packages": [ { "name": "container-interop/container-interop", @@ -39,21 +39,24 @@ }, { "name": "erusev/parsedown", - "version": "1.6.3", + "version": "1.6.4", "source": { "type": "git", "url": "https://github.com/erusev/parsedown.git", - "reference": "728952b90a333b5c6f77f06ea9422b94b585878d" + "reference": "fbe3fe878f4fe69048bb8a52783a09802004f548" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/erusev/parsedown/zipball/728952b90a333b5c6f77f06ea9422b94b585878d", - "reference": "728952b90a333b5c6f77f06ea9422b94b585878d", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/fbe3fe878f4fe69048bb8a52783a09802004f548", + "reference": "fbe3fe878f4fe69048bb8a52783a09802004f548", "shasum": "" }, "require": { "php": ">=5.3.0" }, + "require-dev": { + "phpunit/phpunit": "^4.8.35" + }, "type": "library", "autoload": { "psr-0": { @@ -77,7 +80,7 @@ "markdown", "parser" ], - "time": "2017-05-14T14:47:48+00:00" + "time": "2017-11-14T20:44:03+00:00" }, { "name": "erusev/parsedown-extra", @@ -538,6 +541,69 @@ ], "time": "2017-09-20T19:47:37+00:00" }, + { + "name": "symfony/event-dispatcher", + "version": "v3.3.12", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "271d8c27c3ec5ecee6e2ac06016232e249d638d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/271d8c27c3ec5ecee6e2ac06016232e249d638d9", + "reference": "271d8c27c3ec5ecee6e2ac06016232e249d638d9", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "conflict": { + "symfony/dependency-injection": "<3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.8|~3.0", + "symfony/dependency-injection": "~3.3", + "symfony/expression-language": "~2.8|~3.0", + "symfony/stopwatch": "~2.8|~3.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com", + "time": "2017-11-05T15:47:03+00:00" + }, { "name": "symfony/yaml", "version": "v2.8.30", diff --git a/system/Controllers/Controller.php b/system/Controllers/Controller.php index d7687e2..1340b53 100644 --- a/system/Controllers/Controller.php +++ b/system/Controllers/Controller.php @@ -4,6 +4,7 @@ namespace Typemill\Controllers; /* Use the slim-container */ use Interop\Container\ContainerInterface; +use Typemill\Events\RenderSiteEvent; abstract class Controller { @@ -14,10 +15,15 @@ abstract class Controller $this->c = $c; } - protected function render404($response, $content = NULL) + protected function render($response, $route, $data) { - return $this->c->view->render($response->withStatus(404), '/404.twig', $content); + $data = $this->c->dispatcher->dispatch('beforeRenderSite', new RenderSiteEvent($data))->getData(); + + return $this->c->view->render($response, $route, $data); } -} - -?> \ No newline at end of file + + protected function render404($response, $data = NULL) + { + return $this->c->view->render($response->withStatus(404), '/404.twig', $data); + } +} \ No newline at end of file diff --git a/system/Controllers/PageController.php b/system/Controllers/PageController.php index bdbfdcf..4542ff1 100644 --- a/system/Controllers/PageController.php +++ b/system/Controllers/PageController.php @@ -9,12 +9,14 @@ use Typemill\Models\WriteYaml; use \Symfony\Component\Yaml\Yaml; use Typemill\Models\VersionCheck; use Typemill\Models\Helpers; +use Typemill\Events\LoadStructureEvent; +use Typemill\Events\LoadMarkdownEvent; +use Typemill\Events\ParseHtmlEvent; class PageController extends Controller { public function index($request, $response, $args) - { - + { /* Initiate Variables */ $structure = false; $contentHTML = false; @@ -29,38 +31,39 @@ class PageController extends Controller try { + /* if the cached structure is still valid, use it */ if($cache->validate('cache', 'lastCache.txt',600)) - { + { $structure = $this->getCachedStructure($cache); $cached = true; } else { + /* if not, get a fresh structure of the content folder */ $structure = $this->getFreshStructure($pathToContent, $cache, $uri); - $cached = false; + $cached = false; + + /* if there is no structure at all, the content folder is probably empty */ if(!$structure) - { + { $content = '
Your content folder is empty.
'; - $this->c->view->render($response, '/index.twig', [ 'content' => $content ]); + + $this->render($response, '/index.twig', [ 'content' => $content ]); } elseif(!$cache->validate('cache', 'lastSitemap.txt', 86400)) - { + { /* update sitemap */ $sitemap = new WriteSitemap(); $sitemap->updateSitemap('cache', 'sitemap.xml', 'lastSitemap.txt', $structure, $uri->getBaseUrl()); - $version = new VersionCheck(); - $latestVersion = $version->checkVersion($uri->getBaseUrl()); - if($latestVersion) - { - $yaml = new WriteYaml(); - $yamlContent = $yaml->getYaml('settings', 'settings.yaml'); - $yamlContent['latestVersion'] = $latestVersion; - $yaml->updateYaml('settings', 'settings.yaml', $yamlContent); - } + /* check and update the typemill-version in the user settings */ + $this->updateVersion($uri->getBaseUrl()); } } + + /* dispatch event and let others manipulate the structure */ + $structure = $this->c->dispatcher->dispatch('onStructureLoaded', new LoadStructureEvent($structure))->getData(); } catch (Exception $e) { @@ -81,21 +84,28 @@ class PageController extends Controller /* find the url in the content-item-tree and return the item-object for the file */ $item = Folder::getItemForUrl($structure, $urlRel); - - if(!$item && $cached) + + /* if structure is cached and there is no item + if($cached && !$item) { + /* get a fresh structure and search for the item again $structure = $this->getFreshStructure($pathToContent, $cache, $uri); $item = Folder::getItemForUrl($structure, $urlRel); } - if(!$item){ return $this->render404($response, array( 'navigation' => $structure, 'settings' => $settings, 'base_url' => $base_url )); } + + /* if there is still no item, return a 404-page */ + if(!$item) + { + return $this->render404($response, array( 'navigation' => $structure, 'settings' => $settings, 'base_url' => $base_url )); + } /* get breadcrumb for page */ $breadcrumb = Folder::getBreadcrumb($structure, $item->keyPathArray); - + /* add the paging to the item */ $item = Folder::getPagingForItem($structure, $item); - - /* check if url is a folder. If so, check if there is an index-file for the folder */ + + /* check if url is a folder. If so, check if there is an index-file in that folder */ if($item->elementType == 'folder' && $item->index) { $filePath = $pathToContent . $item->path . DIRECTORY_SEPARATOR . 'index.md'; @@ -104,16 +114,20 @@ class PageController extends Controller { $filePath = $pathToContent . $item->path; } - + /* read the content of the file */ $contentMD = isset($filePath) ? file_get_contents($filePath) : false; } + $contentMD = $this->c->dispatcher->dispatch('onMarkdownLoaded', new LoadMarkdownEvent($contentMD))->getData(); + /* initialize parsedown */ $Parsedown = new \ParsedownExtra(); - + /* parse markdown-file to html-string */ $contentHTML = $Parsedown->text($contentMD); + $contentHTML = $this->c->dispatcher->dispatch('onHtmlParsed', new ParseHtmlEvent($contentHTML))->getData(); + $excerpt = substr($contentHTML,0,200); $excerpt = explode("", $excerpt); $title = isset($excerpt[0]) ? strip_tags($excerpt[0]) : $settings['title']; @@ -127,8 +141,8 @@ class PageController extends Controller */ $route = empty($args) && $settings['startpage'] ? '/cover.twig' : '/index.twig'; - - $this->c->view->render($response, $route, array('navigation' => $structure, 'content' => $contentHTML, 'item' => $item, 'breadcrumb' => $breadcrumb, 'settings' => $settings, 'title' => $title, 'description' => $description, 'base_url' => $base_url )); + + $this->render($response, $route, array('navigation' => $structure, 'content' => $contentHTML, 'item' => $item, 'breadcrumb' => $breadcrumb, 'settings' => $settings, 'title' => $title, 'description' => $description, 'base_url' => $base_url )); } protected function getCachedStructure($cache) @@ -155,4 +169,28 @@ class PageController extends Controller return $structure; } + + protected function updateVersion($baseUrl) + { + /* check the latest public typemill version */ + $version = new VersionCheck(); + $latestVersion = $version->checkVersion($baseUrl); + + if($latestVersion) + { + /* check, if user-settings exist */ + $yaml = new WriteYaml(); + $userSettings = $yaml->getYaml('settings', 'settings.yaml'); + if($userSettings) + { + /* if there is no version info in the settings or if the version info is outdated */ + if(!isset($userSettings['latestVersion']) || $userSettings['latestVersion'] != $latestVersion) + { + /* write the latest version into the user-settings */ + $userSettings['latestVersion'] = $latestVersion; + $yaml->updateYaml('settings', 'settings.yaml', $userSettings); + } + } + } + } } \ No newline at end of file diff --git a/system/Events/LoadMarkdownEvent.php b/system/Events/LoadMarkdownEvent.php new file mode 100644 index 0000000..6982408 --- /dev/null +++ b/system/Events/LoadMarkdownEvent.php @@ -0,0 +1,29 @@ +data = $data; + } + + public function getData() + { + return $this->data; + } + + public function setData($data) + { + $this->data = $data; + } +} \ No newline at end of file diff --git a/system/Events/LoadStructureEvent.php b/system/Events/LoadStructureEvent.php new file mode 100644 index 0000000..e7c6b88 --- /dev/null +++ b/system/Events/LoadStructureEvent.php @@ -0,0 +1,29 @@ +data = $data; + } + + public function getData() + { + return $this->data; + } + + public function setData($data) + { + $this->data = $data; + } +} \ No newline at end of file diff --git a/system/Events/ParseHtmlEvent.php b/system/Events/ParseHtmlEvent.php new file mode 100644 index 0000000..79e9c98 --- /dev/null +++ b/system/Events/ParseHtmlEvent.php @@ -0,0 +1,29 @@ +data = $data; + } + + public function getData() + { + return $this->data; + } + + public function setData($data) + { + $this->data = $data; + } +} \ No newline at end of file diff --git a/system/Events/RenderSiteEvent.php b/system/Events/RenderSiteEvent.php new file mode 100644 index 0000000..6717701 --- /dev/null +++ b/system/Events/RenderSiteEvent.php @@ -0,0 +1,29 @@ +data = $data; + } + + public function getData() + { + return $this->data; + } + + public function setData($data) + { + $this->data = $data; + } +} \ No newline at end of file diff --git a/system/Models/VersionCheck.php b/system/Models/VersionCheck.php index 9ecb67e..aeb9859 100644 --- a/system/Models/VersionCheck.php +++ b/system/Models/VersionCheck.php @@ -18,7 +18,7 @@ class VersionCheck try { $version = file_get_contents('http://typemill.net/tma1/checkversion', false, $context); - if ($version) + if ($version) { $version = json_decode($version); return $version->version; diff --git a/system/Models/WriteCache.php b/system/Models/WriteCache.php index 7966c6a..9721618 100644 --- a/system/Models/WriteCache.php +++ b/system/Models/WriteCache.php @@ -10,7 +10,7 @@ class WriteCache extends Write * @return boolean for an invalid cache (false) and for a valid cache (true). */ public function validate($folderName, $fileName, $duration) - { + { if(isset($_SERVER['HTTP_CACHE_CONTROL']) && $_SERVER['HTTP_CACHE_CONTROL'] == 'max-age=0') { return false; @@ -26,7 +26,7 @@ class WriteCache extends Write $this->writeFile($folderName, $fileName, time()); return false; } - + $lastRefresh = file_get_contents($folderName . DIRECTORY_SEPARATOR . $fileName); if(time() - $lastRefresh > $duration) diff --git a/system/Plugin.php b/system/Plugin.php new file mode 100644 index 0000000..04627a0 --- /dev/null +++ b/system/Plugin.php @@ -0,0 +1,43 @@ +container = $container; + $this->app = $app; + } + + protected function getRoute() + { + return $this->container['request']->getUri(); + } + + protected function getPath() + { + $route = $this->container['request']->getUri(); + return $route->getPath(); + } + + protected function getDispatcher($dispatcher) + { + return $dispatcher; + } + +} diff --git a/system/Plugins.php b/system/Plugins.php new file mode 100644 index 0000000..d2fdb49 --- /dev/null +++ b/system/Plugins.php @@ -0,0 +1,93 @@ +scanPluginFolder(); + $classNames = array(); + + /* iterate over plugin folders */ + foreach($pluginFolder as $plugin) + { + + $className = DIRECTORY_SEPARATOR . 'Plugins' . DIRECTORY_SEPARATOR . $plugin . DIRECTORY_SEPARATOR . $plugin; + + /* if plugin-class and subscribe-method exists, add classname to array */ + if(class_exists($className) /* && method_exists($className, 'getSubscribedEvents') */) + { + $classNames[] = $className; + } + } + return $classNames; + } + + public function getNewRoutes($className, $routes) + { + + /* if route-method exists in plugin-class */ + if(method_exists($className, 'addNewRoutes')) + { + /* add the routes */ + $pluginRoutes = $className::addNewRoutes(); + + /* multi-dimensional or simple array of routes */ + if(isset($pluginRoutes[0])) + { + /* if they are properly formatted, add them to routes array */ + foreach($pluginRoutes as $pluginRoute) + { + if($this->checkRouteArray($pluginRoute)) + { + $routes[] = $pluginRoute; + } + } + } + elseif(is_array($routes)) + { + if($this->checkRouteArray($pluginRoutes)) + { + $routes[] = $pluginRoutes; + } + } + } + + return $routes; + } + + public function getNewMiddleware($className) + { + if(method_exists($className, 'addNewMiddleware')) + { + /* check array */ + return $className::addNewMiddleware(); + } + } + + private function checkRouteArray($route) + { + if( + isset($route['httpMethod']) AND in_array($route['httpMethod'], array('get','post','put','delete','head','patch','options')) + AND isset($route['route']) AND is_string($route['route']) + AND isset($route['class']) AND is_string($route['class'])) + { + return true; + } + return false; + } + + private function scanPluginFolder() + { + $pluginsDir = __DIR__ . '/../plugins'; + + /* check if plugins directory exists */ + if(!is_dir($pluginsDir)){ return array(); } + + /* get all plugins folder */ + $plugins = array_diff(scandir($pluginsDir), array('..', '.')); + + return $plugins; + } +} \ No newline at end of file diff --git a/system/Routes/web.php b/system/Routes/web.php index 38eb60c..02cea58 100644 --- a/system/Routes/web.php +++ b/system/Routes/web.php @@ -9,4 +9,13 @@ if(!isset($userSettings)) $app->post('/setup', SetupController::class . ':save')->setName('save'); } +foreach($routes as $pluginRoute) +{ + $method = $pluginRoute['httpMethod']; + $route = $pluginRoute['route']; + $class = $pluginRoute['class']; + + $app->{$method}($route, $class); +} + $app->get('/[{params:.*}]', PageController::class . ':index'); \ No newline at end of file diff --git a/system/settings.php b/system/settings.php index 16bc118..16da800 100644 --- a/system/settings.php +++ b/system/settings.php @@ -1,22 +1,58 @@ 'TYPEMILL', - 'author' => 'Unknown', - 'copyright' => 'Copyright', - 'startpage' => true, - 'rootPath' => __DIR__ . DS . '..' . DS, - 'theme' => ($theme = 'typemill'), - 'themeFolder' => ($themeFolder = 'themes'), - 'themeBasePath' => __DIR__ . DS . '..' . DS, - 'themePath' => __DIR__ . DS . '..' . DS . $themeFolder . DS . $theme, - 'settingsPath' => __DIR__ . DS . '..' . DS . 'settings', - 'authorPath' => __DIR__ . DS . 'author' . DS, - 'contentFolder' => 'content', - 'displayErrorDetails' => false, - 'version' => '1.0.3' -]; +class Settings +{ + public static function loadSettings() + { + $settings = self::getDefaultSettings(); + $userSettings = self::getUserSettings($settings['settingsPath']); + + if($userSettings) + { + $settings = array_merge($settings, $userSettings); + } + $settings['themePath'] = $settings['rootPath'] . $settings['themeFolder'] . DIRECTORY_SEPARATOR . $settings['theme']; + return array('settings' => $settings); + } + + private function getDefaultSettings() + { + $rootPath = __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR; + + return [ + 'determineRouteBeforeAppMiddleware' => true, + 'displayErrorDetails' => true, + 'title' => 'TYPEMILL', + 'author' => 'Unknown', + 'copyright' => 'Copyright', + 'startpage' => true, + 'rootPath' => $rootPath, + 'theme' => ($theme = 'typemill'), + 'themeFolder' => ($themeFolder = 'themes'), + 'themeBasePath' => $rootPath, + 'themePath' => $rootPath . $themeFolder . DIRECTORY_SEPARATOR . $theme, + 'settingsPath' => $rootPath . 'settings', + 'authorPath' => __DIR__ . DIRECTORY_SEPARATOR . 'author' . DIRECTORY_SEPARATOR, + 'contentFolder' => 'content', + 'version' => '1.0.3' + ]; + } + + private function getUserSettings($settingsPath) + { + if(file_exists($settingsPath . DIRECTORY_SEPARATOR . 'settings.yaml')) + { + $yaml = new \Symfony\Component\Yaml\Parser(); -?> \ No newline at end of file + try { + $userSettings = $yaml->parse( file_get_contents($settingsPath . DIRECTORY_SEPARATOR . 'settings.yaml' ) ); + } catch (ParseException $e) { + printf("Unable to parse the YAML string: %s", $e->getMessage()); + } + return $userSettings; + } + return false; + } +} \ No newline at end of file diff --git a/system/system.php b/system/system.php index ed590d4..1472f37 100644 --- a/system/system.php +++ b/system/system.php @@ -1,5 +1,8 @@ parse( file_get_contents($settings['settingsPath'] . DIRECTORY_SEPARATOR . 'settings.yaml' ) ); - } catch (ParseException $e) { - printf("Unable to parse the YAML string: %s", $e->getMessage()); - } - - $settings = array_merge($settings, $userSettings); - $settings['themePath'] = $settings['themeBasePath'] . $settings['themeFolder'] . DIRECTORY_SEPARATOR . $settings['theme']; -} - -$settings['settings'] = $settings; +$settings = Typemill\Settings::loadSettings(); /************************ * INITIATE SLIM * @@ -35,14 +22,15 @@ $settings['settings'] = $settings; $app = new \Slim\App($settings); /************************ -* SLIM CONTAINER * +* GET SLIM CONTAINER * ************************/ $container = $app->getContainer(); /************************ -* LOAD TWIG * +* LOAD TWIG VIEW * ************************/ + $container['view'] = function ($container) use ($settings){ $path = array($settings['settings']['themePath'], $settings['settings']['authorPath']); @@ -66,8 +54,37 @@ $container['flash'] = function () { return new \Slim\Flash\Messages(); }; +/**************************** +* CREATE EVENT DISPATCHER * +****************************/ + +$dispatcher = new \Symfony\Component\EventDispatcher\EventDispatcher(); + /************************ -* NOT FOUND HANDLER * +* LOAD PLUGINS * +************************/ + +$plugins = new Typemill\Plugins(); +$pluginClassNames = $plugins->load(); +$routes = $middleware = array(); + +foreach($pluginClassNames as $pluginClassName) +{ + $routes = $plugins->getNewRoutes($pluginClassName, $routes); + $middleware[] = $plugins->getNewMiddleware($pluginClassName); + + $dispatcher->addSubscriber(new $pluginClassName($container, $app)); +} + +$dispatcher->dispatch('onPluginsInitialized'); + +$container['dispatcher'] = function($container) use ($dispatcher) +{ + return $dispatcher; +}; + +/************************ +* ADD MIDDLEWARE * ************************/ $container['notFoundHandler'] = function($c) @@ -75,7 +92,11 @@ $container['notFoundHandler'] = function($c) return new \Typemill\Handlers\NotFoundHandler($c['view']); }; +/************************ +* ADD ROUTES * +************************/ + +$timer['before router']=microtime(true); + require __DIR__ . '/Routes/api.php'; require __DIR__ . '/Routes/web.php'; - -?> \ No newline at end of file diff --git a/system/vendor/composer/autoload_psr4.php b/system/vendor/composer/autoload_psr4.php index 5537dec..5aeb42e 100644 --- a/system/vendor/composer/autoload_psr4.php +++ b/system/vendor/composer/autoload_psr4.php @@ -9,11 +9,13 @@ return array( 'Typemill\\' => array($baseDir . '/system'), 'Twig\\' => array($vendorDir . '/twig/twig/src'), 'Symfony\\Component\\Yaml\\' => array($vendorDir . '/symfony/yaml'), + 'Symfony\\Component\\EventDispatcher\\' => array($vendorDir . '/symfony/event-dispatcher'), 'Slim\\Views\\' => array($vendorDir . '/slim/twig-view/src'), 'Slim\\Flash\\' => array($vendorDir . '/slim/flash/src'), 'Slim\\' => array($vendorDir . '/slim/slim/Slim'), 'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'), 'Psr\\Container\\' => array($vendorDir . '/psr/container/src'), + 'Plugins\\' => array($baseDir . '/plugins'), 'Interop\\Container\\' => array($vendorDir . '/container-interop/container-interop/src/Interop/Container'), 'FastRoute\\' => array($vendorDir . '/nikic/fast-route/src'), ); diff --git a/system/vendor/composer/autoload_static.php b/system/vendor/composer/autoload_static.php index 9eceadc..da3be67 100644 --- a/system/vendor/composer/autoload_static.php +++ b/system/vendor/composer/autoload_static.php @@ -19,6 +19,7 @@ class ComposerStaticInit836351be733ecbf4741aea17e1973480 'S' => array ( 'Symfony\\Component\\Yaml\\' => 23, + 'Symfony\\Component\\EventDispatcher\\' => 34, 'Slim\\Views\\' => 11, 'Slim\\Flash\\' => 11, 'Slim\\' => 5, @@ -27,6 +28,7 @@ class ComposerStaticInit836351be733ecbf4741aea17e1973480 array ( 'Psr\\Http\\Message\\' => 17, 'Psr\\Container\\' => 14, + 'Plugins\\' => 8, ), 'I' => array ( @@ -51,6 +53,10 @@ class ComposerStaticInit836351be733ecbf4741aea17e1973480 array ( 0 => __DIR__ . '/..' . '/symfony/yaml', ), + 'Symfony\\Component\\EventDispatcher\\' => + array ( + 0 => __DIR__ . '/..' . '/symfony/event-dispatcher', + ), 'Slim\\Views\\' => array ( 0 => __DIR__ . '/..' . '/slim/twig-view/src', @@ -71,6 +77,10 @@ class ComposerStaticInit836351be733ecbf4741aea17e1973480 array ( 0 => __DIR__ . '/..' . '/psr/container/src', ), + 'Plugins\\' => + array ( + 0 => __DIR__ . '/../../..' . '/plugins', + ), 'Interop\\Container\\' => array ( 0 => __DIR__ . '/..' . '/container-interop/container-interop/src/Interop/Container', diff --git a/system/vendor/composer/installed.json b/system/vendor/composer/installed.json index 2ddc844..c1cd926 100644 --- a/system/vendor/composer/installed.json +++ b/system/vendor/composer/installed.json @@ -423,50 +423,6 @@ "description": "Symfony Yaml Component", "homepage": "https://symfony.com" }, - { - "name": "erusev/parsedown", - "version": "1.6.3", - "version_normalized": "1.6.3.0", - "source": { - "type": "git", - "url": "https://github.com/erusev/parsedown.git", - "reference": "728952b90a333b5c6f77f06ea9422b94b585878d" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/erusev/parsedown/zipball/728952b90a333b5c6f77f06ea9422b94b585878d", - "reference": "728952b90a333b5c6f77f06ea9422b94b585878d", - "shasum": "" - }, - "require": { - "php": ">=5.3.0" - }, - "time": "2017-05-14T14:47:48+00:00", - "type": "library", - "installation-source": "source", - "autoload": { - "psr-0": { - "Parsedown": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Emanuil Rusev", - "email": "hello@erusev.com", - "homepage": "http://erusev.com" - } - ], - "description": "Parser for Markdown.", - "homepage": "http://parsedown.org", - "keywords": [ - "markdown", - "parser" - ] - }, { "name": "slim/twig-view", "version": "2.3.0", @@ -670,5 +626,117 @@ "parsedown", "parser" ] + }, + { + "name": "erusev/parsedown", + "version": "1.6.4", + "version_normalized": "1.6.4.0", + "source": { + "type": "git", + "url": "https://github.com/erusev/parsedown.git", + "reference": "fbe3fe878f4fe69048bb8a52783a09802004f548" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/erusev/parsedown/zipball/fbe3fe878f4fe69048bb8a52783a09802004f548", + "reference": "fbe3fe878f4fe69048bb8a52783a09802004f548", + "shasum": "" + }, + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "^4.8.35" + }, + "time": "2017-11-14T20:44:03+00:00", + "type": "library", + "installation-source": "source", + "autoload": { + "psr-0": { + "Parsedown": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Emanuil Rusev", + "email": "hello@erusev.com", + "homepage": "http://erusev.com" + } + ], + "description": "Parser for Markdown.", + "homepage": "http://parsedown.org", + "keywords": [ + "markdown", + "parser" + ] + }, + { + "name": "symfony/event-dispatcher", + "version": "v3.3.12", + "version_normalized": "3.3.12.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "271d8c27c3ec5ecee6e2ac06016232e249d638d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/271d8c27c3ec5ecee6e2ac06016232e249d638d9", + "reference": "271d8c27c3ec5ecee6e2ac06016232e249d638d9", + "shasum": "" + }, + "require": { + "php": "^5.5.9|>=7.0.8" + }, + "conflict": { + "symfony/dependency-injection": "<3.3" + }, + "require-dev": { + "psr/log": "~1.0", + "symfony/config": "~2.8|~3.0", + "symfony/dependency-injection": "~3.3", + "symfony/expression-language": "~2.8|~3.0", + "symfony/stopwatch": "~2.8|~3.0" + }, + "suggest": { + "symfony/dependency-injection": "", + "symfony/http-kernel": "" + }, + "time": "2017-11-05T15:47:03+00:00", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.3-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony EventDispatcher Component", + "homepage": "https://symfony.com" } ] diff --git a/system/vendor/erusev/parsedown b/system/vendor/erusev/parsedown index 728952b..fbe3fe8 160000 --- a/system/vendor/erusev/parsedown +++ b/system/vendor/erusev/parsedown @@ -1 +1 @@ -Subproject commit 728952b90a333b5c6f77f06ea9422b94b585878d +Subproject commit fbe3fe878f4fe69048bb8a52783a09802004f548 diff --git a/system/vendor/symfony/event-dispatcher/.gitignore b/system/vendor/symfony/event-dispatcher/.gitignore new file mode 100644 index 0000000..c49a5d8 --- /dev/null +++ b/system/vendor/symfony/event-dispatcher/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/system/vendor/symfony/event-dispatcher/CHANGELOG.md b/system/vendor/symfony/event-dispatcher/CHANGELOG.md new file mode 100644 index 0000000..736bd84 --- /dev/null +++ b/system/vendor/symfony/event-dispatcher/CHANGELOG.md @@ -0,0 +1,37 @@ +CHANGELOG +========= + +3.3.0 +----- + + * The ContainerAwareEventDispatcher class has been deprecated. Use EventDispatcher with closure factories instead. + +3.0.0 +----- + + * The method `getListenerPriority($eventName, $listener)` has been added to the + `EventDispatcherInterface`. + * The methods `Event::setDispatcher()`, `Event::getDispatcher()`, `Event::setName()` + and `Event::getName()` have been removed. + The event dispatcher and the event name are passed to the listener call. + +2.5.0 +----- + + * added Debug\TraceableEventDispatcher (originally in HttpKernel) + * changed Debug\TraceableEventDispatcherInterface to extend EventDispatcherInterface + * added RegisterListenersPass (originally in HttpKernel) + +2.1.0 +----- + + * added TraceableEventDispatcherInterface + * added ContainerAwareEventDispatcher + * added a reference to the EventDispatcher on the Event + * added a reference to the Event name on the event + * added fluid interface to the dispatch() method which now returns the Event + object + * added GenericEvent event class + * added the possibility for subscribers to subscribe several times for the + same event + * added ImmutableEventDispatcher diff --git a/system/vendor/symfony/event-dispatcher/ContainerAwareEventDispatcher.php b/system/vendor/symfony/event-dispatcher/ContainerAwareEventDispatcher.php new file mode 100644 index 0000000..313db4a --- /dev/null +++ b/system/vendor/symfony/event-dispatcher/ContainerAwareEventDispatcher.php @@ -0,0 +1,197 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\EventDispatcher; + +use Symfony\Component\DependencyInjection\ContainerInterface; + +/** + * Lazily loads listeners and subscribers from the dependency injection + * container. + * + * @author Fabien Potencier
+ */
+class EventDispatcher implements EventDispatcherInterface
+{
+ private $listeners = array();
+ private $sorted = array();
+
+ /**
+ * {@inheritdoc}
+ */
+ public function dispatch($eventName, Event $event = null)
+ {
+ if (null === $event) {
+ $event = new Event();
+ }
+
+ if ($listeners = $this->getListeners($eventName)) {
+ $this->doDispatch($listeners, $eventName, $event);
+ }
+
+ return $event;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getListeners($eventName = null)
+ {
+ if (null !== $eventName) {
+ if (empty($this->listeners[$eventName])) {
+ return array();
+ }
+
+ if (!isset($this->sorted[$eventName])) {
+ $this->sortListeners($eventName);
+ }
+
+ return $this->sorted[$eventName];
+ }
+
+ foreach ($this->listeners as $eventName => $eventListeners) {
+ if (!isset($this->sorted[$eventName])) {
+ $this->sortListeners($eventName);
+ }
+ }
+
+ return array_filter($this->sorted);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getListenerPriority($eventName, $listener)
+ {
+ if (empty($this->listeners[$eventName])) {
+ return;
+ }
+
+ if (is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) {
+ $listener[0] = $listener[0]();
+ }
+
+ foreach ($this->listeners[$eventName] as $priority => $listeners) {
+ foreach ($listeners as $k => $v) {
+ if ($v !== $listener && is_array($v) && isset($v[0]) && $v[0] instanceof \Closure) {
+ $v[0] = $v[0]();
+ $this->listeners[$eventName][$priority][$k] = $v;
+ }
+ if ($v === $listener) {
+ return $priority;
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hasListeners($eventName = null)
+ {
+ if (null !== $eventName) {
+ return !empty($this->listeners[$eventName]);
+ }
+
+ foreach ($this->listeners as $eventListeners) {
+ if ($eventListeners) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addListener($eventName, $listener, $priority = 0)
+ {
+ $this->listeners[$eventName][$priority][] = $listener;
+ unset($this->sorted[$eventName]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function removeListener($eventName, $listener)
+ {
+ if (empty($this->listeners[$eventName])) {
+ return;
+ }
+
+ if (is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) {
+ $listener[0] = $listener[0]();
+ }
+
+ foreach ($this->listeners[$eventName] as $priority => $listeners) {
+ foreach ($listeners as $k => $v) {
+ if ($v !== $listener && is_array($v) && isset($v[0]) && $v[0] instanceof \Closure) {
+ $v[0] = $v[0]();
+ }
+ if ($v === $listener) {
+ unset($listeners[$k], $this->sorted[$eventName]);
+ } else {
+ $listeners[$k] = $v;
+ }
+ }
+
+ if ($listeners) {
+ $this->listeners[$eventName][$priority] = $listeners;
+ } else {
+ unset($this->listeners[$eventName][$priority]);
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function addSubscriber(EventSubscriberInterface $subscriber)
+ {
+ foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
+ if (is_string($params)) {
+ $this->addListener($eventName, array($subscriber, $params));
+ } elseif (is_string($params[0])) {
+ $this->addListener($eventName, array($subscriber, $params[0]), isset($params[1]) ? $params[1] : 0);
+ } else {
+ foreach ($params as $listener) {
+ $this->addListener($eventName, array($subscriber, $listener[0]), isset($listener[1]) ? $listener[1] : 0);
+ }
+ }
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function removeSubscriber(EventSubscriberInterface $subscriber)
+ {
+ foreach ($subscriber->getSubscribedEvents() as $eventName => $params) {
+ if (is_array($params) && is_array($params[0])) {
+ foreach ($params as $listener) {
+ $this->removeListener($eventName, array($subscriber, $listener[0]));
+ }
+ } else {
+ $this->removeListener($eventName, array($subscriber, is_string($params) ? $params : $params[0]));
+ }
+ }
+ }
+
+ /**
+ * Triggers the listeners of an event.
+ *
+ * This method can be overridden to add functionality that is executed
+ * for each listener.
+ *
+ * @param callable[] $listeners The event listeners
+ * @param string $eventName The name of the event to dispatch
+ * @param Event $event The event object to pass to the event handlers/listeners
+ */
+ protected function doDispatch($listeners, $eventName, Event $event)
+ {
+ foreach ($listeners as $listener) {
+ if ($event->isPropagationStopped()) {
+ break;
+ }
+ call_user_func($listener, $event, $eventName, $this);
+ }
+ }
+
+ /**
+ * Sorts the internal list of listeners for the given event by priority.
+ *
+ * @param string $eventName The name of the event
+ */
+ private function sortListeners($eventName)
+ {
+ krsort($this->listeners[$eventName]);
+ $this->sorted[$eventName] = array();
+
+ foreach ($this->listeners[$eventName] as $priority => $listeners) {
+ foreach ($listeners as $k => $listener) {
+ if (is_array($listener) && isset($listener[0]) && $listener[0] instanceof \Closure) {
+ $listener[0] = $listener[0]();
+ $this->listeners[$eventName][$priority][$k] = $listener;
+ }
+ $this->sorted[$eventName][] = $listener;
+ }
+ }
+ }
+}
diff --git a/system/vendor/symfony/event-dispatcher/EventDispatcherInterface.php b/system/vendor/symfony/event-dispatcher/EventDispatcherInterface.php
new file mode 100644
index 0000000..d3d0cb8
--- /dev/null
+++ b/system/vendor/symfony/event-dispatcher/EventDispatcherInterface.php
@@ -0,0 +1,93 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\EventDispatcher;
+
+/**
+ * The EventDispatcherInterface is the central point of Symfony's event listener system.
+ * Listeners are registered on the manager and events are dispatched through the
+ * manager.
+ *
+ * @author Bernhard Schussek