From 4c8741f263233c7ce2355bf32600c445bbf57f80 Mon Sep 17 00:00:00 2001 From: Awilum Date: Wed, 21 Mar 2018 01:38:54 +0300 Subject: [PATCH] NEW BRAND NAME - FLEXTYPE --- flextype/Cache.php | 227 ++++++++++++++++++++++++++++++++++++++++ flextype/Config.php | 112 ++++++++++++++++++++ flextype/Events.php | 101 ++++++++++++++++++ flextype/Filters.php | 125 ++++++++++++++++++++++ flextype/Flextype.php | 136 ++++++++++++++++++++++++ flextype/I18n.php | 145 +++++++++++++++++++++++++ flextype/Markdown.php | 42 ++++++++ flextype/Pages.php | 207 ++++++++++++++++++++++++++++++++++++ flextype/Plugins.php | 104 ++++++++++++++++++ flextype/Shortcodes.php | 131 +++++++++++++++++++++++ flextype/Templates.php | 47 +++++++++ flextype/Themes.php | 58 ++++++++++ 12 files changed, 1435 insertions(+) create mode 100755 flextype/Cache.php create mode 100755 flextype/Config.php create mode 100644 flextype/Events.php create mode 100755 flextype/Filters.php create mode 100755 flextype/Flextype.php create mode 100644 flextype/I18n.php create mode 100644 flextype/Markdown.php create mode 100755 flextype/Pages.php create mode 100755 flextype/Plugins.php create mode 100644 flextype/Shortcodes.php create mode 100644 flextype/Templates.php create mode 100644 flextype/Themes.php diff --git a/flextype/Cache.php b/flextype/Cache.php new file mode 100755 index 00000000..d07f858f --- /dev/null +++ b/flextype/Cache.php @@ -0,0 +1,227 @@ + + * @link http://flextype.org + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +class Cache +{ + /** + * An instance of the Cache class + * + * @var object + */ + protected static $instance = null; + /** + * Unique cache key + * + * @var string Cache key. + */ + protected static $key; + /** + * Lifetime + * + * @var int Lifetime. + */ + protected static $lifetime; + /** + * Current time + * + * @var int Current time. + */ + protected static $now; + /** + * Cache Driver + * + * @var DoctrineCache + */ + protected static $driver; + /** + * Protected clone method to enforce singleton behavior. + * + * @access protected + */ + protected function __clone() + { + // Nothing here. + } + /** + * Constructor. + * + * @access protected + */ + protected function __construct() + { + // Set current time + static::$now = time(); + // Cache key allows us to invalidate all cache on configuration changes. + static::$key = (Config::get('site.cache.prefix') ? Config::get('site.cache.prefix') : 'fansoro') . '-' . md5(ROOT_DIR . 'Fansoro::VERSION'); + // Get Cache Driver + static::$driver = static::getCacheDriver(); + // Set the cache namespace to our unique key + static::$driver->setNamespace(static::$key); + } + /** + * Get Cache Driver + * + * @access public + * @return object + */ + public static function getCacheDriver() + { + $driver_name = Config::get('site.cache.driver'); + if (!$driver_name || $driver_name == 'auto') { + if (extension_loaded('apc')) { + $driver_name = 'apc'; + } elseif (extension_loaded('wincache')) { + $driver_name = 'wincache'; + } elseif (extension_loaded('xcache')) { + $driver_name = 'xcache'; + } + } else { + $driver_name = 'file'; + } + switch ($driver_name) { + case 'apc': + $driver = new \Doctrine\Common\Cache\ApcCache(); + break; + case 'wincache': + $driver = new \Doctrine\Common\Cache\WinCacheCache(); + break; + case 'xcache': + $driver = new \Doctrine\Common\Cache\XcacheCache(); + break; + case 'memcache': + $memcache = new \Memcache(); + $memcache->connect(Config::get('site.cache.memcache.server', 'localhost'), + Config::get('site.cache.memcache.port', 11211)); + $driver = new \Doctrine\Common\Cache\MemcacheCache(); + $driver->setMemcache($memcache); + break; + case 'redis': + $redis = new \Redis(); + $redis->connect(Config::get('site.cache.redis.server', 'localhost'), + Config::get('site.cache.redis.port', 6379)); + $driver = new \Doctrine\Common\Cache\RedisCache(); + $driver->setRedis($redis); + break; + default: + // Create doctrine cache directory if its not exists + !Flextype::$filesystem->exists($cache_directory = CACHE_PATH . '/doctrine/') and Flextype::$filesystem->mkdir($cache_directory); + $driver = new \Doctrine\Common\Cache\FilesystemCache($cache_directory); + break; + } + return $driver; + } + + /** + * Returns driver variable + * + * @access public + * @return object + */ + public static function driver() + { + return static::$driver; + } + /** + * Get cache key. + * + * @access public + * @return string + */ + public static function getKey() + { + return static::$key; + } + /** + * Fetches an entry from the cache. + * + * @access public + * @param string $id The id of the cache entry to fetch. + * @return mixed The cached data or FALSE, if no cache entry exists for the given id. + */ + public function fetch($id) + { + if (Config::get('site.cache.enabled')) { + return static::$driver->fetch($id); + } else { + return false; + } + } + /** + * Puts data into the cache. + * + * @access public + * @param string $id The cache id. + * @param mixed $data The cache entry/data. + * @param int $lifeTime The lifetime in number of seconds for this cache entry. + * If zero (the default), the entry never expires (although it may be deleted from the cache + * to make place for other entries). + */ + public function save($id, $data, $lifetime = null) + { + if (Config::get('site.cache.enabled')) { + if ($lifetime === null) { + $lifetime = static::getLifetime(); + } + static::$driver->save($id, $data, $lifetime); + } + } + /** + * Clear Cache + */ + public static function clear() + { + Flextype::$filesystem->remove(CACHE_PATH . '/doctrine/'); + } + /** + * Set the cache lifetime. + * + * @access public + * @param int $future timestamp + */ + public static function setLifetime($future) + { + if (!$future) { + return; + } + $interval = $future - $this->now; + if ($interval > 0 && $interval < static::getLifetime()) { + static::$lifetime = $interval; + } + } + /** + * Retrieve the cache lifetime (in seconds) + * + * @access public + * @return mixed + */ + public static function getLifetime() + { + if (static::$lifetime === null) { + static::$lifetime = Config::get('site.cache.lifetime') ?: 604800; + } + return static::$lifetime; + } + /** + * Initialize Fansoro Cache + * + * + * Cache::init(); + * + * + * @access public + * @return object + */ + public static function init() + { + return !isset(self::$instance) and self::$instance = new Cache(); + } +} diff --git a/flextype/Config.php b/flextype/Config.php new file mode 100755 index 00000000..ae493e28 --- /dev/null +++ b/flextype/Config.php @@ -0,0 +1,112 @@ + + * @link http://flextype.org + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +class Config +{ + + /** + * An instance of the Config class + * + * @var object + * @access protected + */ + protected static $instance = null; + + /** + * Config + * + * @var array + * @access protected + */ + protected static $config = []; + + /** + * Protected clone method to enforce singleton behavior. + * + * @access protected + */ + protected function __clone() + { + // Nothing here. + } + + /** + * Constructor. + * + * @access protected + */ + protected function __construct() + { + if (Flextype::$filesystem->exists($site_config = CONFIG_PATH . '/' . 'site.yml')) { + static::$config['site'] = Yaml::parse(file_get_contents($site_config)); + } else { + throw new RuntimeException("Flextype site config file does not exist."); + } + } + + /** + * Set new or update existing config variable + * + * @access public + * @param string $key Key + * @param mixed $value Value + */ + public static function set($key, $value) + { + Arr::set(static::$config, $key, $value); + } + + /** + * Get config variable + * + * @access public + * @param string $key Key + * @param mixed $default Default value + * @return mixed + */ + public static function get($key, $default = null) + { + return Arr::get(static::$config, $key, $default); + } + + /** + * Get config array + * + * + * $config = Config::getConfig(); + * + * + * @access public + * @return array + */ + public static function getConfig() + { + return static::$config; + } + + /** + * Initialize Flextype Config + * + * + * Config::init(); + * + * + * @access public + */ + public static function init() + { + return !isset(self::$instance) and self::$instance = new Config(); + } +} diff --git a/flextype/Events.php b/flextype/Events.php new file mode 100644 index 00000000..b2949c1d --- /dev/null +++ b/flextype/Events.php @@ -0,0 +1,101 @@ + + * @link http://flextype.org + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +class Events +{ + + /** + * Events + * + * @var array + * @access protected + */ + protected static $events = []; + + /** + * Protected constructor since this is a static class. + * + * @access protected + */ + protected function __construct() + { + // Nothing here + } + + /** + * Hooks a function on to a specific event. + * + * @access public + * @param string $event_name Event name + * @param mixed $added_function Added function + * @param integer $priority Priority. Default is 10 + * @param array $args Arguments + */ + public static function addListener(string $event_name, $added_function, int $priority = 10, array $args = null) + { + // Hooks a function on to a specific event. + static::$events[] = array( + 'event_name' => $event_name, + 'function' => $added_function, + 'priority' => $priority, + 'args' => $args + ); + } + + /** + * Run functions hooked on a specific event. + * + * @access public + * @param string $event_name Event name + * @param array $args Arguments + * @param boolean $return Return data or not. Default is false + * @return mixed + */ + public static function dispatch(string $event_name, array $args = [], bool $return = false) + { + // Redefine arguments + $event_name = $event_name; + $return = $return; + + // Run event + if (count(static::$events) > 0) { + + // Sort actions by priority + $events = Arr::subvalSort(static::$events, 'priority'); + + // Loop through $events array + foreach ($events as $action) { + + // Execute specific action + if ($action['event_name'] == $event_name) { + // isset arguments ? + if (isset($args)) { + // Return or Render specific action results ? + if ($return) { + return call_user_func_array($action['function'], $args); + } else { + call_user_func_array($action['function'], $args); + } + } else { + if ($return) { + return call_user_func_array($action['function'], $action['args']); + } else { + call_user_func_array($action['function'], $action['args']); + } + } + } + } + } + } +} diff --git a/flextype/Filters.php b/flextype/Filters.php new file mode 100755 index 00000000..2f78c37d --- /dev/null +++ b/flextype/Filters.php @@ -0,0 +1,125 @@ + + * @link http://flextype.org + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +class Filters +{ + + /** + * @var Flextype + */ + protected $flextype; + + /** + * Filters + * + * @var array + * @access protected + */ + protected static $filters = []; + + + /** + * Protected constructor since this is a static class. + * + * @access protected + */ + protected function __construct() + { + // Nothing here + } + + /** + * Dispatch filters + * + * + * Filter::dispatch('content', $content); + * + * + * @access public + * @param string $filter_name The name of the filter hook. + * @param mixed $value The value on which the filters hooked. + * @return mixed + */ + public static function dispatch(string $filter_name, $value) + { + $args = array_slice(func_get_args(), 2); + + if (! isset(static::$filters[$filter_name])) { + return $value; + } + + foreach (static::$filters[$filter_name] as $priority => $functions) { + if (! is_null($functions)) { + foreach ($functions as $function) { + $all_args = array_merge(array($value), $args); + $function_name = $function['function']; + $accepted_args = $function['accepted_args']; + if ($accepted_args == 1) { + $the_args = array($value); + } elseif ($accepted_args > 1) { + $the_args = array_slice($all_args, 0, $accepted_args); + } elseif ($accepted_args == 0) { + $the_args = null; + } else { + $the_args = $all_args; + } + $value = call_user_func_array($function_name, $the_args); + } + } + } + + return $value; + } + + /** + * Add filter + * + * + * Filter::add('content', 'replacer'); + * + * function replacer($content) { + * return preg_replace(array('/\[b\](.*?)\[\/b\]/ms'), array('\1'), $content); + * } + * + * + * @access public + * @param string $filter_name The name of the filter to hook the $function_to_add to. + * @param string $function_to_add The name of the function to be called when the filter is applied. + * @param integer $priority Function to add priority - default is 10. + * @param integer $accepted_args The number of arguments the function accept default is 1. + * @return boolean + */ + public static function addListener($filter_name, $function_to_add, $priority = 10, $accepted_args = 1) + { + // Redefine arguments + $filter_name = (string) $filter_name; + $function_to_add = $function_to_add; + $priority = (int) $priority; + $accepted_args = (int) $accepted_args; + + // Check that we don't already have the same filter at the same priority. Thanks to WP :) + if (isset(static::$filters[$filter_name]["$priority"])) { + foreach (static::$filters[$filter_name]["$priority"] as $filter) { + if ($filter['function'] == $function_to_add) { + return true; + } + } + } + + static::$filters[$filter_name]["$priority"][] = array('function' => $function_to_add, 'accepted_args' => $accepted_args); + + // Sort + ksort(static::$filters[$filter_name]["$priority"]); + + return true; + } +} diff --git a/flextype/Flextype.php b/flextype/Flextype.php new file mode 100755 index 00000000..36f26a2c --- /dev/null +++ b/flextype/Flextype.php @@ -0,0 +1,136 @@ + + * @link http://flextype.org + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +class Flextype +{ + /** + * An instance of the Flextype class + * + * @var object + * @access protected + */ + protected static $instance = null; + + /** + * Filesystem + * + * @var object + * @access public + */ + public static $filesystem = null; + + /** + * Finder + * + * @var object + * @access public + */ + public static $finder = null; + + /** + * Protected clone method to enforce singleton behavior. + * + * @access protected + */ + protected function __clone() + { + // Nothing here. + } + + /** + * The version of Flextype + * + * @var string + */ + const VERSION = '0.0.0'; + + /** + * Constructor. + * + * @access protected + */ + protected function __construct() + { + + static::$finder = new Finder(); + static::$filesystem = new Filesystem(); + + // Init Config + Config::init(); + + // Turn on output buffering + ob_start(); + + // Display Errors + if (Config::get('site.errors.display')) { + define('DEVELOPMENT', true); + error_reporting(-1); + } else { + define('DEVELOPMENT', false); + error_reporting(0); + } + + // Set internal encoding + function_exists('mb_language') and mb_language('uni'); + function_exists('mb_regex_encoding') and mb_regex_encoding(Config::get('site.charset')); + function_exists('mb_internal_encoding') and mb_internal_encoding(Config::get('site.charset')); + + // Set Error handler + set_error_handler('ErrorHandler::error'); + register_shutdown_function('ErrorHandler::fatal'); + set_exception_handler('ErrorHandler::exception'); + + // Set default timezone + date_default_timezone_set(Config::get('site.timezone')); + + // Start the session + Session::start(); + + // Init Cache + Cache::init(); + + // Init I18n + I18n::init(); + + // Init Themes + Themes::init(); + + // Init Plugins + Plugins::init(); + + // Render current page + Pages::init(); + + // Flush (send) the output buffer and turn off output buffering + ob_end_flush(); + } + + /** + * Initialize Flextype Application + * + * + * Rawium::init(); + * + * + * @access public + * @return object + */ + public static function init() + { + return !isset(self::$instance) and self::$instance = new Flextype(); + } +} diff --git a/flextype/I18n.php b/flextype/I18n.php new file mode 100644 index 00000000..e1fc26a6 --- /dev/null +++ b/flextype/I18n.php @@ -0,0 +1,145 @@ + + * @link http://flextype.org + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +class I18n +{ + /** + * An instance of the Cache class + * + * @var object + */ + protected static $instance = null; + + /** + * Locales array + * + * @var array + */ + public static $locales = [ + 'ar' => 'العربية', + 'bg' => 'Български', + 'ca' => 'Català', + 'cs' => 'Česky', + 'da' => 'Dansk', + 'de' => 'Deutsch', + 'el' => 'Ελληνικά', + 'en' => 'English', + 'es' => 'Español', + 'fa' => 'Farsi', + 'fi' => 'Suomi', + 'fr' => 'Français', + 'gl' => 'Galego', + 'ka-ge' => 'Georgian', + 'hu' => 'Magyar', + 'it' => 'Italiano', + 'id' => 'Bahasa Indonesia', + 'ja' => '日本語', + 'lt' => 'Lietuvių', + 'nl' => 'Nederlands', + 'no' => 'Norsk', + 'pl' => 'Polski', + 'pt' => 'Português', + 'pt-br' => 'Português do Brasil', + 'ru' => 'Русский', + 'sk' => 'Slovenčina', + 'sl' => 'Slovenščina', + 'sv' => 'Svenska', + 'sr' => 'Srpski', + 'tr' => 'Türkçe', + 'uk' => 'Українська', + 'zh-cn' => '简体中文', + ]; + + /** + * Dictionary + * + * @var array + */ + public static $dictionary = []; + + /** + * Protected clone method to enforce singleton behavior. + * + * @access protected + */ + protected function __clone() + { + // Nothing here. + } + + /** + * Construct + */ + protected function __construct() + { + + // Get Plugins and Site Locales list + (array) $plugins_list = Config::get('site.plugins'); + (array) $locales = Config::get('site.locales'); + (array) $dictionary = []; + + // Create dictionary + if (is_array($plugins_list) && count($plugins_list) > 0) { + foreach ($locales as $locale) { + foreach ($plugins_list as $plugin) { + $language_file = PLUGINS_PATH . '/' . $plugin . '/languages/' . $locale . '.yml'; + if (file_exists($language_file)) { + $dictionary[$plugin][$locale] = Yaml::parse(file_get_contents($language_file)); + } + } + } + } + + // Save dictionary + static::$dictionary = $dictionary; + } + + /** + * Returns translation of a string. If no translation exists, the original + * string will be returned. No parameters are replaced. + * + * @param string $string Text to translate + * @param string $namespace Namespace + * @param string $locale Locale + * @return string + */ + public static function find(string $string, string $namespace, string $locale, array $values = []) : string + { + // Search current string to translate in the Dictionary + if (isset(static::$dictionary[$namespace][$locale][$string])) { + $string = static::$dictionary[$namespace][$locale][$string]; + $string = empty($values) ? $string : strtr($string, $values); + } else { + $string = $string; + } + + // Return translation of a string + return $string; + } + + /** + * Initialize Flextype I18n + * + * + * I18n::init(); + * + * + * @access public + * @return object + */ + public static function init() + { + return !isset(self::$instance) and self::$instance = new I18n(); + } +} diff --git a/flextype/Markdown.php b/flextype/Markdown.php new file mode 100644 index 00000000..4b7165ea --- /dev/null +++ b/flextype/Markdown.php @@ -0,0 +1,42 @@ + + * @link http://flextype.org + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +class Markdown +{ + /** + * Parsedown Extra Object + * + * @var object + * @access protected + */ + protected static $markdown; + + /** + * Markdown parser + * + * + * $content = Markdown::parse($content); + * + * + * @access public + * @param string $content Content to parse + * @return string Formatted content + */ + public static function parse(string $content) : string + { + !static::$markdown and static::$markdown = new ParsedownExtra(); + + return static::$markdown->text($content); + } +} diff --git a/flextype/Pages.php b/flextype/Pages.php new file mode 100755 index 00000000..f215776a --- /dev/null +++ b/flextype/Pages.php @@ -0,0 +1,207 @@ + + * @link http://flextype.org + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +class Pages +{ + /** + * An instance of the Cache class + * + * @var object + */ + protected static $instance = null; + + /** + * Page + * + * @var Page + */ + public static $page; + + /** + * Constructor + * + * @param Flextype $flextype + */ + protected function __construct() + { + // The page is not processed and not sent to the display. + Events::dispatch('onPageBeforeRender'); + + // Get current page + static::$page = static::getPage(Url::getUriString()); + + // Display page for current requested url + static::renderPage(static::$page); + + // The page has been fully processed and sent to the display. + Events::dispatch('onPageAfterRender'); + } + + /** + * Page finder + */ + public static function finder($url = '', $url_abs = false) + { + + // If url is empty that its a homepage + if ($url_abs) { + if ($url) { + $file = $url; + } else { + $file = PAGES_PATH . '/' . Config::get('site.pages.main') . '/' . 'index.md'; + } + } else { + if ($url) { + $file = PAGES_PATH . '/' . $url . '/index.md'; + } else { + $file = PAGES_PATH . '/' . Config::get('site.pages.main') . '/' . 'index.md'; + } + } + + // Get 404 page if file not exists + if (Flextype::$filesystem->exists($file)) { + $file = $file; + } else { + $file = PAGES_PATH . '/404/index.md'; + Response::status(404); + } + + return $file; + } + + /** + * Render page + */ + public static function renderPage($page) + { + $template_ext = '.php'; + $template_name = empty($page['template']) ? 'index' : $page['template']; + $site_theme = Config::get('site.theme'); + $template_path = THEMES_PATH . '/' . $site_theme . '/' . $template_name . $template_ext; + + if (Flextype::$filesystem->exists($template_path)) { + include $template_path; + } else { + throw new RuntimeException("Template {$template_name} does not exist."); + } + } + + /** + * Page parser + */ + public static function parse($file) + { + $page = trim(file_get_contents($file)); + $page = explode('---', $page, 3); + + $frontmatter = Shortcodes::parse($page[1]); + $result_page = Yaml::parse($frontmatter); + + // Get page url + $url = str_replace(PAGES_PATH, Url::getBase(), $file); + $url = str_replace('index.md', '', $url); + $url = str_replace('.md', '', $url); + $url = str_replace('\\', '/', $url); + $url = rtrim($url, '/'); + $result_page['url'] = $url; + + // Get page slug + $url = str_replace(Url::getBase(), '', $url); + $url = ltrim($url, '/'); + $url = rtrim($url, '/'); + $result_page['slug'] = str_replace(Url::getBase(), '', $url); + + $result_page['content'] = $page[2]; + + return $result_page; + } + + + /** + * Get page + */ + public static function getPage(string $url = '', bool $raw = false, bool $url_abs = false) + { + $file = static::finder($url, $url_abs); + + if ($raw) { + $page = trim(file_get_contents($file)); + static::$page = $page; + Events::dispatch('onPageContentRawAfter'); + } else { + $page = static::parse($file); + static::$page = $page; + static::$page['content'] = Filters::dispatch('content', static::parseContent(static::$page['content'])); + Events::dispatch('onPageContentAfter'); + } + + return static::$page; + } + + public static function parseContent(string $content) : string + { + $content = Shortcodes::parse($content); + $content = Markdown::parse($content); + + return $content; + } + + /** + * getPage + */ + public static function getPages($url = '', $raw = false, $order_by = 'title', $order_type = 'DESC', $limit = null) + { + // Get pages list for current $url + $pages_list = Flextype::$finder->files()->name('*.md')->in(PAGES_PATH . '/' . $url); + + // Go trough pages list + foreach ($pages_list as $key => $page) { + if (strpos($page->getPathname(), $url.'/index.md') !== false) { + + } else { + $pages[$key] = static::getPage($page->getPathname(), $raw, true); + } + } + + // Sort and Slice pages if !$raw + if (!$raw) { + $pages = Arr::subvalSort($pages, $order_by, $order_type); + + if ($limit != null) { + $pages = array_slice($_pages, null, $limit); + } + } + + return $pages; + } + + /** + * Initialize Flextype Pages + * + * + * Pages::init(); + * + * + * @access public + * @return object + */ + public static function init() + { + return !isset(self::$instance) and self::$instance = new Pages(); + } +} diff --git a/flextype/Plugins.php b/flextype/Plugins.php new file mode 100755 index 00000000..e5b9f0c2 --- /dev/null +++ b/flextype/Plugins.php @@ -0,0 +1,104 @@ + + * @link http://flextype.org + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +class Plugins +{ + /** + * An instance of the Cache class + * + * @var object + */ + protected static $instance = null; + + /** + * Init Plugins + * + * @access public + * @return mixed + */ + protected function __construct() + { + // Plugin manifest + $plugin_manifest = []; + + // Plugin cache id + $plugins_cache_id = ''; + + // Get Plugins List + $plugins_list = Config::get('site.plugins'); + + // If Plugins List isnt empty then create plugin cache ID + if (is_array($plugins_list) && count($plugins_list) > 0) { + + // Go through... + foreach ($plugins_list as $plugin) { + if (Flextype::$filesystem->exists($_plugin = PLUGINS_PATH . '/' . $plugin . '/' . $plugin . '.yml')) { + $plugins_cache_id .= filemtime($_plugin); + } + } + + // Create Unique Cache ID for Plugins + $plugins_cache_id = md5('plugins' . PLUGINS_PATH . $plugins_cache_id); + } + + // Get plugins list from cache or scan plugins folder and create new plugins cache item + if (Cache::driver()->contains($plugins_cache_id)) { + Config::set('plugins', Cache::driver()->fetch($plugins_cache_id)); + } else { + + // If Plugins List isnt empty + if (is_array($plugins_list) && count($plugins_list) > 0) { + + // Go through... + foreach ($plugins_list as $plugin) { + + if (Flextype::$filesystem->exists($_plugin_manifest = PLUGINS_PATH . '/' . $plugin . '/' . $plugin . '.yml')) { + $plugin_manifest = Yaml::parseFile($_plugin_manifest); + } + + $_plugins_config[basename($_plugin_manifest, '.yml')] = $plugin_manifest; + } + + Config::set('plugins', $_plugins_config); + Cache::driver()->save($plugins_cache_id, $_plugins_config); + } + } + + // Include enabled plugins + if (is_array(Config::get('plugins')) && count(Config::get('plugins')) > 0) { + foreach (Config::get('plugins') as $plugin_name => $plugin) { + if (Config::get('plugins.'.$plugin_name.'.enabled')) { + include_once PLUGINS_PATH .'/'. $plugin_name .'/'. $plugin_name . '.php'; + } + } + } + + Events::dispatch('onPluginsInitialized'); + } + + /** + * Initialize Flextype Plugins + * + * + * Plugins::init(); + * + * + * @access public + * @return object + */ + public static function init() + { + return !isset(self::$instance) and self::$instance = new Plugins(); + } +} diff --git a/flextype/Shortcodes.php b/flextype/Shortcodes.php new file mode 100644 index 00000000..746f3269 --- /dev/null +++ b/flextype/Shortcodes.php @@ -0,0 +1,131 @@ + + * @link http://flextype.org + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +class Shortcodes +{ + + /** + * Shortcode tags array + * + * @var shortcode_tags + */ + protected static $shortcode_tags = []; + + /** + * Protected constructor since this is a static class. + * + * @access protected + */ + protected function __construct() + { + // Nothing here + } + + /** + * Add new shortcode + * + * @param string $shortcode Shortcode tag to be searched in content. + * @param string $callback_function The callback function to replace the shortcode with. + */ + public static function add(string $shortcode, $callback_function) + { + // Add new shortcode + if (is_callable($callback_function)) { + static::$shortcode_tags[$shortcode] = $callback_function; + } + } + + /** + * Remove a specific registered shortcode. + * + * @param string $shortcode Shortcode tag. + */ + public static function delete(string $shortcode) + { + // Delete shortcode + if (static::exists($shortcode)) { + unset(static::$shortcode_tags[$shortcode]); + } + } + + /** + * Remove all registered shortcodes. + * + * + * Shortcode::clear(); + * + * + */ + public static function clear() + { + static::$shortcode_tags = array(); + } + + /** + * Check if a shortcode has been registered. + * + * @param string $shortcode Shortcode tag. + */ + public static function exists(string $shortcode) + { + // Check shortcode + return array_key_exists($shortcode, static::$shortcode_tags); + } + + /** + * Parse a string, and replace any registered shortcodes within it with the result of the mapped callback. + * + * @param string $content Content + * @return string + */ + public static function parse(string $content) + { + if (! static::$shortcode_tags) { + return $content; + } + + $shortcodes = implode('|', array_map('preg_quote', array_keys(static::$shortcode_tags))); + $pattern = "/(.?)\{([$shortcodes]+)(.*?)(\/)?\}(?(4)|(?:(.+?)\{\/\s*\\2\s*\}))?(.?)/s"; + + return preg_replace_callback($pattern, 'static::_handle', $content); + } + + /** + * _handle() + */ + protected static function _handle($matches) + { + $prefix = $matches[1]; + $suffix = $matches[6]; + $shortcode = $matches[2]; + + // Allow for escaping shortcodes by enclosing them in {{shortcode}} + if ($prefix == '{' && $suffix == '}') { + return substr($matches[0], 1, -1); + } + + $attributes = array(); // Parse attributes into into this array. + + if (preg_match_all('/(\w+) *= *(?:([\'"])(.*?)\\2|([^ "\'>]+))/', $matches[3], $match, PREG_SET_ORDER)) { + foreach ($match as $attribute) { + if (! empty($attribute[4])) { + $attributes[strtolower($attribute[1])] = $attribute[4]; + } elseif (! empty($attribute[3])) { + $attributes[strtolower($attribute[1])] = $attribute[3]; + } + } + } + + // Check if this shortcode realy exists then call user function else return empty string + return (isset(static::$shortcode_tags[$shortcode])) ? $prefix . call_user_func(static::$shortcode_tags[$shortcode], $attributes, $matches[5], $shortcode) . $suffix : ''; + } +} diff --git a/flextype/Templates.php b/flextype/Templates.php new file mode 100644 index 00000000..4ddfbc68 --- /dev/null +++ b/flextype/Templates.php @@ -0,0 +1,47 @@ + + * @link http://flextype.org + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +class Templates +{ + + /** + * Protected constructor since this is a static class. + * + * @access protected + */ + protected function __construct() + { + // Nothing here + } + + /** + * Get Themes template + * + * @access public + * @param string $template_name Template name + * @return mixed + */ + public static function display(string $template_name) + { + $template_ext = '.php'; + + $page = Pages::$page; + + $template_path = THEMES_PATH . '/' . Config::get('site.theme') . '/' . $template_name . $template_ext; + + if (Flextype::$filesystem->exists($template_path)) { + include $template_path; + } else { + throw new RuntimeException("Template {$template_name} does not exist."); + } + } +} diff --git a/flextype/Themes.php b/flextype/Themes.php new file mode 100644 index 00000000..7b01da29 --- /dev/null +++ b/flextype/Themes.php @@ -0,0 +1,58 @@ + + * @link http://flextype.org + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +class Themes +{ + /** + * An instance of the Themes class + * + * @var object + */ + protected static $instance = null; + + /** + * Init Themes + * + * @access public + * @return mixed + */ + protected function __construct() + { + // Theme Manifest + $theme_manifest = []; + + // Get current theme + $theme = Config::get('site.theme'); + + if (Flextype::$filesystem->exists($theme_manifest_file = THEMES_PATH . '/' . $theme . '/' . $theme . '.yml')) { + $theme_manifest = Yaml::parseFile($theme_manifest_file); + Config::set('themes.'.Config::get('site.theme'), $theme_manifest); + } + } + + /** + * Initialize Flextype Themes + * + * + * Themes::init(); + * + * + * @access public + * @return object + */ + public static function init() + { + return !isset(self::$instance) and self::$instance = new Themes(); + } +}