1
0
mirror of https://github.com/flextype/flextype.git synced 2025-08-08 14:16:46 +02:00

Merge branch 'dev'

# Conflicts:
#	flextype/Cache.php
This commit is contained in:
Awilum
2018-05-05 13:09:40 +03:00
30 changed files with 360 additions and 718 deletions

View File

@@ -1,3 +1,20 @@
# Flextype 0.3.0, 2018-05-05
* Using Flextype Components instead of Symphony Components
* Available Flextype Components for developers: Arr, Assets, Cookie, Date, Debug, ErrorHandler, Event, Filesystem, Html, Http, I18n, Notification, Number, Registry, Session, Text, Token, View.
* Using `.yaml` files instead of `.yml`
* Default theme from now is `simple`
* Themes structure is changed. From now main folder for all theme templates and partials is `views` inside theme folder.
* Templates moved to `/simple/views/templates/` and partials moved to `/simple/views/partials/`
* Default template changes from `index.php` to `default.php`
* Plugins templates can be overridden by templates in themes folder.
* For pages we will not use `index.md` anymore. From now page file will have a name `page.md`
* Config class was removed, from now we will use simple powerful Registry Component to access configurations.
* Event, Filter, View class was removed. From now we are using more powerful Flextype Components!
* Fixed issue with getPages() method.
* Twitter Bootstrap updated to 4.1.0 for default theme.
* ErrorHandler added with errors logs.
* Code cleanup and refactoring #5
# Flextype 0.2.1, 2018-03-26
* date_format setting added to /site/config.site.yml
* Pages: Fixed bug with pages sort and slice in getPages() method

View File

@@ -1,5 +1,5 @@
# Flextype
![version](https://img.shields.io/badge/version-0.2.1-brightgreen.svg?style=flat-square "Version")
![version](https://img.shields.io/badge/version-0.3.0-brightgreen.svg?style=flat-square "Version")
[![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)](https://github.com/flextype/flextype/blob/master/LICENSE.txt)
Flextype is next generation of Legendary Monstra Engine it is also Open Source, fast and flexible file-based Content Management System. That's Easy to install, upgrade and use. Flextype provides amazing API's for plugins, themes and core developers! Content in Flextype is just a simple files written with markdown syntax in pages folder. You simply create markdown files in the pages folder and that becomes a page.

View File

@@ -1,8 +1,8 @@
{
"name": "flextype/flextype",
"type": "project",
"description": "Flextype is Modern Open Source Flat-File Content Management System",
"keywords": ["Flextype", "php", "cms", "flat-file cms", "flat cms", "flatfile cms", "markdown"],
"description": "Flextype is The Best Open Source Flat-File Content Management System",
"keywords": ["flextype", "php", "cms", "flat-file cms", "flat cms", "flatfile cms", "markdown"],
"homepage": "http://flextype.org",
"license": "MIT",
"authors": [
@@ -19,17 +19,26 @@
"php": ">=7.1.3",
"erusev/parsedown": "1.7.0",
"erusev/parsedown-extra": "0.7.1",
"doctrine/cache": "1.7.1",
"symfony/yaml": "4.0.4",
"symfony/filesystem": "4.0.4",
"symfony/finder": "4.0.4",
"thunderer/shortcode": "0.6.5",
"force/session" : "*",
"force/arr" : "*",
"force/http" : "*",
"force/token" : "*",
"force/errorhandler" : "*",
"force/url" : "*"
"doctrine/cache": "1.*",
"symfony/yaml": "4.*",
"thunderer/shortcode": "0.*",
"flextype-components/arr" : "1.*",
"flextype-components/assets" : "1.*",
"flextype-components/cookie" : "1.*",
"flextype-components/date" : "1.*",
"flextype-components/debug" : "1.*",
"flextype-components/event" : "1.*",
"flextype-components/errorhandler" : "1.*",
"flextype-components/filesystem" : "1.*",
"flextype-components/i18n" : "1.*",
"flextype-components/http" : "1.*",
"flextype-components/html" : "1.*",
"flextype-components/number" : "1.*",
"flextype-components/notification" : "1.*",
"flextype-components/registry" : "1.*",
"flextype-components/token" : "1.*",
"flextype-components/view" : "1.*",
"flextype-components/text" : "1.*"
},
"autoload": {
"classmap": [

View File

@@ -1,106 +0,0 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <awilum@yandex.ru>
* @link http://flextype.org
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
use Arr;
use Symfony\Component\Yaml\Yaml;
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) : void
{
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
*
* @access public
* @return array
*/
public static function getConfig() : array
{
return static::$config;
}
/**
* Initialize Flextype Config
*
* @access public
*/
public static function init()
{
return !isset(self::$instance) and self::$instance = new Config();
}
}

View File

@@ -1,104 +0,0 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <awilum@yandex.ru>
* @link http://flextype.org
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
use Arr;
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
* @return void
*/
public static function addListener(string $event_name, $added_function, int $priority = 10, array $args = null) : void
{
// 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']);
}
}
}
}
}
}
}

View File

@@ -1,114 +0,0 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <awilum@yandex.ru>
* @link http://flextype.org
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
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
}
/**
* Add filter
*
* @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 bool
*/
public static function addListener($filter_name, $function_to_add, $priority = 10, $accepted_args = 1) : bool
{
// 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;
}
/**
* Dispatch filters
*
* @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;
}
}

View File

@@ -12,9 +12,8 @@
namespace Flextype;
use Symfony\Component\{Filesystem\Filesystem, Finder\Finder};
use Url;
use Session;
use Flextype\Component\{Http\Http, Session\Session, ErrorHandler\ErrorHandler, Registry\Registry, Filesystem\Filesystem};
use Symfony\Component\Yaml\Yaml;
class Flextype
{
@@ -26,22 +25,6 @@ class Flextype
*/
protected static $instance = null;
/**
* Filesystem object
*
* @var Filesystem
* @access public
*/
public static $filesystem = null;
/**
* Finder object
*
* @var Finder
* @access public
*/
public static $finder = null;
/**
* Protected clone method to enforce singleton behavior.
*
@@ -66,30 +49,31 @@ class Flextype
*/
protected function __construct()
{
static::app();
static::init();
}
/**
* Application.
* Init Application
*
* @access protected
*/
protected static function app() : void
protected static function init() : void
{
// Init Finder
static::$finder = new Finder();
// Init Filesystem
static::$filesystem = new Filesystem();
// Init Config
Config::init();
// Turn on output buffering
ob_start();
// Set empty site item
Registry::set('site', []);
// Set site items if site config exists
if (Filesystem::fileExists($site_config = CONFIG_PATH . '/' . 'site.yaml')) {
Registry::set('site', Yaml::parseFile($site_config));
} else {
throw new \RuntimeException("Flextype site config file does not exist.");
}
// Display Errors
if (Config::get('site.errors.display')) {
if (Registry::get('site.errors.display')) {
define('DEVELOPMENT', true);
error_reporting(-1);
} else {
@@ -99,71 +83,47 @@ class Flextype
// 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'));
function_exists('mb_regex_encoding') and mb_regex_encoding(Registry::get('site.charset'));
function_exists('mb_internal_encoding') and mb_internal_encoding(Registry::get('site.charset'));
// Set Error handler
set_error_handler('ErrorHandler::error');
register_shutdown_function('ErrorHandler::fatal');
set_exception_handler('ErrorHandler::exception');
set_error_handler('Flextype\Component\ErrorHandler\ErrorHandler::error');
register_shutdown_function('Flextype\Component\ErrorHandler\ErrorHandler::fatal');
set_exception_handler('Flextype\Component\ErrorHandler\ErrorHandler::exception');
// Set default timezone
date_default_timezone_set(Config::get('site.timezone'));
date_default_timezone_set(Registry::get('site.timezone'));
// Start the session
Session::start();
// Init Cache
Cache::init();
// Create Cache Instance
Cache::instance();
// Init I18n
I18n::init();
// Create Shortcodes Instance
Shortcodes::instance();
// Init Shortcodes
Shortcodes::init();
// Create Themes Instance
Themes::instance();
// Init Themes
Themes::init();
// Create Plugins Instance
Plugins::instance();
// Init Plugins
Plugins::init();
// Init Pages
Pages::init();
// Create Pages Instance
Pages::instance();
// Flush (send) the output buffer and turn off output buffering
ob_end_flush();
}
/**
* Returns filesystem object
* Return the Flextype instance.
* Create it if it's not already created.
*
* @access public
* @return Filesystem
* @return object
*/
public static function filesystem() : Filesystem
{
return static::$filesystem;
}
/**
* Returns finder object
*
* @access public
* @return Finder
*/
public static function finder() : Finder
{
return static::$finder;
}
/**
* Initialize Flextype Application
*
* @access public
* @return object
*/
public static function init()
public static function instance()
{
return !isset(self::$instance) and self::$instance = new Flextype();
}

View File

@@ -1,143 +0,0 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <awilum@yandex.ru>
* @link http://flextype.org
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
use Symfony\Component\Yaml\Yaml;
class I18n
{
/**
* An instance of the I18n 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
*
* @access public
* @return object
*/
public static function init()
{
return !isset(self::$instance) and self::$instance = new I18n();
}
}

View File

@@ -12,9 +12,7 @@
namespace Flextype;
use Arr;
use Url;
use Response;
use Flextype\Component\{Arr\Arr, Http\Http, Filesystem\Filesystem, Event\Event, Registry\Registry};
use Symfony\Component\Yaml\Yaml;
class Pages
@@ -34,23 +32,37 @@ class Pages
public static $page;
/**
* Constructor
* Protected constructor since this is a static class.
*
* @access protected
*/
protected function __construct()
{
static::init();
}
/**
* Init Pages
*
* @access protected
* @return void
*/
protected static function init() : void
{
// The page is not processed and not sent to the display.
Events::dispatch('onPageBeforeRender');
Event::dispatch('onPageBeforeRender');
// Add parseContent on content event
Event::addListener('content', 'Flextype\Pages::parseContent');
// Get current page
static::$page = static::getPage(Url::getUriString());
static::$page = static::getPage(Http::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');
Event::dispatch('onPageAfterRender');
}
/**
@@ -66,22 +78,22 @@ class Pages
if ($url) {
$file = $url;
} else {
$file = PAGES_PATH . '/' . Config::get('site.pages.main') . '/' . 'index.md';
$file = PAGES_PATH . '/' . Registry::get('site.pages.main') . '/' . 'page.md';
}
} else {
if ($url) {
$file = PAGES_PATH . '/' . $url . '/index.md';
$file = PAGES_PATH . '/' . $url . '/page.md';
} else {
$file = PAGES_PATH . '/' . Config::get('site.pages.main') . '/' . 'index.md';
$file = PAGES_PATH . '/' . Registry::get('site.pages.main') . '/' . 'page.md';
}
}
// Get 404 page if file not exists
if (Flextype::filesystem()->exists($file)) {
if (Filesystem::fileExists($file)) {
$file = $file;
} else {
$file = PAGES_PATH . '/404/index.md';
Response::status(404);
$file = PAGES_PATH . '/404/page.md';
Http::setResponseStatus(404);
}
return $file;
@@ -92,16 +104,9 @@ class Pages
*/
public static function renderPage(array $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.");
}
Themes::template(empty($page['template']) ? 'templates/default' : 'templates/' . $page['template'])
->assign('page', $page, true)
->display();
}
/**
@@ -109,33 +114,33 @@ class Pages
*/
public static function parseFile(string $file) : array
{
$page = trim(file_get_contents($file));
$page = trim(Filesystem::getFileContent($file));
$page = explode('---', $page, 3);
$frontmatter = Shortcodes::driver()->process($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(PAGES_PATH, Http::getBaseUrl(), $file);
$url = str_replace('page.md', '', $url);
$url = str_replace('.md', '', $url);
$url = str_replace('\\', '/', $url);
$url = str_replace('///', '/', $url);
$url = str_replace('//', '/', $url);
$url = str_replace('http:/', 'http://', $url);
$url = str_replace('https:/', 'https://', $url);
$url = str_replace('/'.Config::get('site.pages.main'), '', $url);
$url = str_replace('/'.Registry::get('site.pages.main'), '', $url);
$url = rtrim($url, '/');
$result_page['url'] = $url;
// Get page slug
$url = str_replace(Url::getBase(), '', $url);
$url = str_replace(Http::getBaseUrl(), '', $url);
$url = ltrim($url, '/');
$url = rtrim($url, '/');
$result_page['slug'] = str_replace(Url::getBase(), '', $url);
$result_page['slug'] = str_replace(Http::getBaseUrl(), '', $url);
// Set page date
$result_page['date'] = $result_page['date'] ?? date(Config::get('site.date_format'), filemtime($file));
$result_page['date'] = $result_page['date'] ?? date(Registry::get('site.date_format'), filemtime($file));
// Set page content
$result_page['content'] = $page[2];
@@ -153,14 +158,14 @@ class Pages
$file = static::finder($url, $url_abs);
if ($raw) {
$page = trim(file_get_contents($file));
$page = trim(Filesystem::getFileContent($file));
static::$page = $page;
Events::dispatch('onPageContentRawAfter');
Event::dispatch('onPageContentRawAfter');
} else {
$page = static::parseFile($file);
static::$page = $page;
static::$page['content'] = Filters::dispatch('content', static::parseContent(static::$page['content']));
Events::dispatch('onPageContentAfter');
static::$page['content'] = Event::dispatch('content', ['content' => static::$page['content']], true);
Event::dispatch('onPageContentAfter');
}
return static::$page;
@@ -193,24 +198,24 @@ class Pages
if ($url == '') {
// Get pages list
$pages_list = Flextype::finder()->files()->name('*.md')->in(PAGES_PATH);
$pages_list = Filesystem::getFilesList(PAGES_PATH, 'md');
// Create pages array from pages list
foreach ($pages_list as $key => $page) {
$pages[$key] = static::getPage($page->getPathname(), $raw, true);
$pages[$key] = static::getPage($page, $raw, true);
}
} else {
// Get pages list
$pages_list = Flextype::finder()->files()->name('*.md')->in(PAGES_PATH . '/' . $url);
$pages_list = Filesystem::getFilesList(PAGES_PATH . '/' . $url, 'md');
// Create pages array from pages list and ignore current requested page
foreach ($pages_list as $key => $page) {
if (strpos($page->getPathname(), $url.'/index.md') !== false) {
if (strpos($page, $url.'/page.md') !== false) {
// ignore ...
} else {
$pages[$key] = static::getPage($page->getPathname(), $raw, true);
$pages[$key] = static::getPage($page, $raw, true);
}
}
@@ -218,7 +223,7 @@ class Pages
// Sort and Slice pages if $raw === false
if (!$raw) {
$pages = Arr::subvalSort($pages, $order_by, $order_type);
$pages = Arr::sort($pages, $order_by, $order_type);
if ($offset !== null && $length !== null) {
$pages = array_slice($pages, $offset, $length);
@@ -230,12 +235,13 @@ class Pages
}
/**
* Initialize Flextype Pages
* Return the Pages instance.
* Create it if it's not already created.
*
* @access public
* @return object
*/
public static function init()
public static function instance()
{
return !isset(self::$instance) and self::$instance = new Pages();
}

View File

@@ -12,6 +12,7 @@
namespace Flextype;
use Flextype\Component\{Filesystem\Filesystem, Event\Event, I18n\I18n, Registry\Registry};
use Symfony\Component\Yaml\Yaml;
class Plugins
@@ -24,11 +25,62 @@ class Plugins
protected static $instance = null;
/**
* Init Plugins
* Locales array
*
* @access public
* @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' => '简体中文',
];
/**
* Protected constructor since this is a static class.
*
* @access protected
*/
protected function __construct()
{
static::init();
}
/**
* Init Plugins
*
* @access protected
* @return void
*/
protected static function init() : void
{
// Plugin manifest
$plugin_manifest = [];
@@ -37,14 +89,17 @@ class Plugins
$plugins_cache_id = '';
// Get Plugins List
$plugins_list = Config::get('site.plugins');
$plugins_list = Registry::get('site.plugins');
// Set empty plugins item
Registry::set('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')) {
if (Filesystem::fileExists($_plugin = PLUGINS_PATH . '/' . $plugin . '/' . $plugin . '.yaml')) {
$plugins_cache_id .= filemtime($_plugin);
}
}
@@ -55,7 +110,7 @@ class Plugins
// 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));
Registry::set('plugins', Cache::driver()->fetch($plugins_cache_id));
} else {
// If Plugins List isnt empty
@@ -64,37 +119,50 @@ class Plugins
// Go through...
foreach ($plugins_list as $plugin) {
if (Flextype::filesystem()->exists($_plugin_manifest = PLUGINS_PATH . '/' . $plugin . '/' . $plugin . '.yml')) {
if (Filesystem::fileExists($_plugin_manifest = PLUGINS_PATH . '/' . $plugin . '/' . $plugin . '.yaml')) {
$plugin_manifest = Yaml::parseFile($_plugin_manifest);
}
$_plugins_config[basename($_plugin_manifest, '.yml')] = $plugin_manifest;
$_plugins_config[basename($_plugin_manifest, '.yaml')] = $plugin_manifest;
}
Config::set('plugins', $_plugins_config);
Registry::set('plugins', $_plugins_config);
Cache::driver()->save($plugins_cache_id, $_plugins_config);
}
}
// Create dictionary
if (is_array($plugins_list) && count($plugins_list) > 0) {
foreach (static::$locales as $locale => $locale_title) {
foreach ($plugins_list as $plugin) {
$language_file = PLUGINS_PATH . '/' . $plugin . '/languages/' . $locale . '.yaml';
if (Filesystem::fileExists($language_file)) {
I18n::add($plugin, $locale, Yaml::parseFile($language_file));
}
}
}
}
// 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')) {
if (is_array(Registry::get('plugins')) && count(Registry::get('plugins')) > 0) {
foreach (Registry::get('plugins') as $plugin_name => $plugin) {
if (Registry::get('plugins.'.$plugin_name.'.enabled')) {
include_once PLUGINS_PATH .'/'. $plugin_name .'/'. $plugin_name . '.php';
}
}
}
Events::dispatch('onPluginsInitialized');
Event::dispatch('onPluginsInitialized');
}
/**
* Initialize Flextype Plugins
* Return the Plugins instance.
* Create it if it's not already created.
*
* @access public
* @return object
*/
public static function init()
public static function instance()
{
return !isset(self::$instance) and self::$instance = new Plugins();
}

View File

@@ -13,7 +13,7 @@
namespace Flextype;
use Thunder\Shortcode\ShortcodeFacade;
use Url;
use Flextype\Component\Http\Http;
class Shortcodes
{
@@ -38,6 +38,17 @@ class Shortcodes
* @access protected
*/
protected function __construct()
{
static::init();
}
/**
* Init Shortcodes
*
* @access protected
* @return void
*/
protected static function init() : void
{
// Set driver
static::$driver = new ShortcodeFacade();
@@ -65,17 +76,18 @@ class Shortcodes
protected static function registerDefaultShortcodes() : void
{
static::driver()->addHandler('site_url', function() {
return Url::getBase();
return Http::getBaseUrl();
});
}
/**
* Initialize Flextype Shortcodes
* Return the Shortcodes instance.
* Create it if it's not already created.
*
* @access public
* @return object
*/
public static function init()
public static function instance()
{
return !isset(self::$instance) and self::$instance = new Shortcodes();
}

View File

@@ -1,49 +0,0 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <awilum@yandex.ru>
* @link http://flextype.org
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
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.");
}
}
}

View File

@@ -12,6 +12,7 @@
namespace Flextype;
use Flextype\Component\{Filesystem\Filesystem, View\View, Registry\Registry};
use Symfony\Component\Yaml\Yaml;
class Themes
@@ -24,32 +25,80 @@ class Themes
protected static $instance = null;
/**
* Init Themes
* Protected constructor since this is a static class.
*
* @access public
* @return mixed
* @access protected
*/
protected function __construct()
{
static::init();
}
/**
* Init Themes
*
* @access protected
* @return void
*/
protected static function init() : void
{
// Theme Manifest
$theme_manifest = [];
// Get current theme
$theme = Config::get('site.theme');
// Theme cache id
$theme_cache_id = '';
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);
// Get current theme
$theme = Registry::get('site.theme');
// Set empty theme item
Registry::set('theme', []);
// Create Unique Cache ID for Theme
$theme_cache_id = md5('theme' . THEMES_PATH . $theme);
if (Cache::driver()->contains($theme_cache_id)) {
Registry::set('themes.'.Registry::get('site.theme'), Cache::driver()->fetch($theme_cache_id));
} else {
if (Filesystem::fileExists($theme_manifest_file = THEMES_PATH . '/' . $theme . '/' . $theme . '.yaml')) {
$theme_manifest = Yaml::parseFile($theme_manifest_file);
Registry::set('themes.'.Registry::get('site.theme'), $theme_manifest);
Cache::driver()->save($theme_cache_id, $theme_manifest);
}
}
}
/**
* Initialize Flextype Themes
* Return the Themes instance.
* Create it if it's not already created.
*
* @param string $template Template file
* @param string $variables Variables
* @access public
* @return object
*/
public static function template(string $template, array $variables = [])
{
// Set view file
// From current theme folder or from plugin folder
if (Filesystem::fileExists(THEMES_PATH . '/' . Registry::get('site.theme') . '/views/' . $template . View::$view_ext)) {
$template = THEMES_PATH . '/' . Registry::get('site.theme') . '/views/' . $template;
} else {
$template = PLUGINS_PATH . '/views/' . $template;
}
// Return template
return new View($template, $variables);
}
/**
* Return the Themes instance.
* Create it if it's not already created.
*
* @access public
* @return object
*/
public static function init()
public static function instance()
{
return !isset(self::$instance) and self::$instance = new Themes();
}

View File

@@ -35,3 +35,6 @@ define('CACHE_PATH', SITE_PATH . '/cache');
// Define the path to the logs directory (without trailing slash).
define('LOGS_PATH', SITE_PATH . '/logs');
// Define the path to the logs directory (without trailing slash).
define('ACCOUNTS_PATH', SITE_PATH . '/accounts');

View File

@@ -25,4 +25,4 @@ version_compare($ver = PHP_VERSION, $req = FLEXTYPE_MINIMUM_PHP, '<') and exit(s
$loader = require_once $autoload;
// Init Flextype
Flextype::init();
Flextype::instance();

View File

@@ -11,12 +11,11 @@ timezone: UTC
date_format: "F d Y H:i:s."
charset: UTF-8
theme: default
theme: simple
plugins:
locale: "en"
locales: [en]
pages:
flush_cache: false

View File

@@ -1,14 +1,14 @@
---
title: Welcome
description: Flextype is a simple and light-weighted Content Management System
template: index
template: default
---
## Flextype is succesfully installed!
You can start editing the content and customising your site.
### Edit this Page
To edit this page, simply go to the folder you installed Flextype, and then browse to the `/site/pages/home/` folder and open the `index.md` file in your editor.
To edit this page, simply go to the folder you installed Flextype, and then browse to the `/site/pages/home/` folder and open the `page.md` file in your editor.
### Create a New page
Creating a new page is very simple in Flextype.
@@ -24,6 +24,7 @@ Creating a new page is very simple in Flextype.
This is the body of **My New Page**
```
2. Save this file in the `/site/pages/my-new-page/` folder as `index.md` and its will be available by this url: [site_url]/my-new-page
2. Save this file in the `/site/pages/my-new-page/` folder as `page.md` and its will be available by this url: [site_url]/my-new-page
That is it!

View File

@@ -1,3 +0,0 @@
<?php Flextype\Templates::display('partials/head'); ?>
<?php echo $page['content']; ?>
<?php Flextype\Templates::display('partials/footer'); ?>

View File

@@ -1,24 +0,0 @@
<!doctype html>
<html lang="<?php echo Flextype\Config::get('site.locale'); ?>">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="<?php echo Flextype\Config::get('site.description'); ?>">
<meta name="author" content="">
<?php Flextype\Events::dispatch('onThemeMeta'); ?>
<title><?php echo $page['title']; ?> | <?php echo Flextype\Config::get('site.title'); ?></title>
<link href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,600,700' rel='stylesheet' type='text/css'>
<!-- Bootstrap core CSS -->
<link href="<?php echo Url::getBase(); ?>/site/themes/<?php echo Flextype\Config::get('site.theme'); ?>/node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="<?php echo Url::getBase(); ?>/site/themes/<?php echo Flextype\Config::get('site.theme'); ?>/assets/css/theme.css" rel="stylesheet">
<?php Flextype\Events::dispatch('onThemeHeader'); ?>
</head>
<body>
<?php Flextype\Templates::display('partials/navigation'); ?>
<main role="main" class="container content">

View File

@@ -1,3 +0,0 @@
<script src="<?php echo Url::getBase(); ?>/site/themes/<?php echo Flextype\Config::get('site.theme'); ?>/node_modules/jquery/dist/jquery.slim.min.js"></script>
<script src="<?php echo Url::getBase(); ?>/site/themes/<?php echo Flextype\Config::get('site.theme'); ?>/node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
<?php Flextype\Events::dispatch('onThemeFooter'); ?>

20
site/themes/simple/package-lock.json generated Normal file
View File

@@ -0,0 +1,20 @@
{
"name": "flextype",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"bootstrap": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.0.0.tgz",
"integrity": "sha512-gulJE5dGFo6Q61V/whS6VM4WIyrlydXfCgkE+Gxe5hjrJ8rXLLZlALq7zq2RPhOc45PSwQpJkrTnc2KgD6cvmA==",
"dev": true
},
"jquery": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/jquery/-/jquery-3.3.1.tgz",
"integrity": "sha512-Ubldcmxp5np52/ENotGxlLe6aGMvmF4R8S6tZjsP6Knsaxd/xp3Zrh50cG93lR6nPXyUFwzN3ZSOQI0wRJNdGg==",
"dev": true
}
}
}

View File

@@ -2,7 +2,7 @@
"name": "flextype",
"version": "1.0.0",
"devDependencies": {
"bootstrap": "^4.0.0",
"bootstrap": "^4.1.0",
"jquery": "^3.3.1"
}
}

View File

@@ -1,6 +1,6 @@
name: Default
name: Simple
version: 1.0.0
description: Default Flextype theme
description: Simple theme for Flextype
author:
name: Sergey Romanenko
email: awilum@yandex.ru

View File

@@ -1,5 +1,6 @@
<?php namespace Flextype; ?>
<?php Flextype\Templates::display('partials/tail'); ?>
<?php Themes::template('partials/tail')->display(); ?>
<div class="powered">
Powered by <a href="http://flextype.org">Flextype</a>

View File

@@ -0,0 +1,28 @@
<?php
namespace Flextype;
use Flextype\Component\{Event\Event, Http\Http, Registry\Registry};
?>
<!doctype html>
<html lang="<?php echo Registry::get('site.locale'); ?>">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="description" content="<?php echo Registry::get('site.description'); ?>">
<meta name="author" content="">
<?php Event::dispatch('onThemeMeta'); ?>
<title><?php echo $page['title']; ?> | <?php echo Registry::get('site.title'); ?></title>
<link href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,600,700' rel='stylesheet' type='text/css'>
<!-- Bootstrap core CSS -->
<link href="<?php echo Http::getBaseUrl(); ?>/site/themes/<?php echo Registry::get('site.theme'); ?>/node_modules/bootstrap/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Custom styles for this template -->
<link href="<?php echo Http::getBaseUrl(); ?>/site/themes/<?php echo Registry::get('site.theme'); ?>/assets/css/theme.css" rel="stylesheet">
<?php Event::dispatch('onThemeHeader'); ?>
</head>
<body>
<?php Themes::template('partials/navigation')->display(); ?>
<main role="main" class="container content">

View File

@@ -1,13 +1,17 @@
<?php
namespace Flextype;
use Flextype\Component\{Http\Http, Registry\Registry};
?>
<nav class="navbar navbar-expand-lg navbar-light bg-white border-bottom box-shadow">
<div class="container">
<a class="navbar-brand" href="<?php echo Url::getBase(); ?>"><?php echo Flextype\Config::get('site.title'); ?></a>
<a class="navbar-brand" href="<?php echo Http::getBaseUrl(); ?>"><?php echo Registry::get('site.title'); ?></a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse justify-content-end" id="navbarNav">
<ul class="navbar-nav">
<li class="nav-item">
<a class="nav-link <?php if (Url::getUriSegment(0) == 'home' || Url::getUriSegment(0) == '') echo 'active'; ?>" href="<?php echo Url::getBase(); ?>">Home</a>
<a class="nav-link <?php if (Http::getUriSegment(0) == 'home' || Http::getUriSegment(0) == '') echo 'active'; ?>" href="<?php echo Http::getBaseUrl(); ?>">Home</a>
</li>
</ul>
</div>

View File

@@ -0,0 +1,7 @@
<?php
namespace Flextype;
use Flextype\Component\{Event\Event, Http\Http, Registry\Registry};
?>
<script src="<?php echo Http::getBaseUrl(); ?>/site/themes/<?php echo Registry::get('site.theme'); ?>/node_modules/jquery/dist/jquery.slim.min.js"></script>
<script src="<?php echo Http::getBaseUrl(); ?>/site/themes/<?php echo Registry::get('site.theme'); ?>/node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
<?php Event::dispatch('onThemeFooter'); ?>

View File

@@ -0,0 +1,4 @@
<?php namespace Flextype; ?>
<?php Themes::template('partials/head')->display(); ?>
<?php echo $page['content']; ?>
<?php Themes::template('partials/footer')->display(); ?>