mirror of
https://github.com/monstra-cms/monstra.git
synced 2025-08-16 18:14:07 +02:00
#431 initial commit for MONSTRA 4
This commit is contained in:
113
monstra/Action.php
Executable file
113
monstra/Action.php
Executable file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Monstra.
|
||||
*
|
||||
* (c) Romanenko Sergey / Awilum <awilum@msn.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
class Action
|
||||
{
|
||||
/**
|
||||
* Actions
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
protected static $actions = [];
|
||||
|
||||
/**
|
||||
* Protected constructor since this is a static class.
|
||||
*
|
||||
* @access protected
|
||||
*/
|
||||
protected function __construct()
|
||||
{
|
||||
// Nothing here
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks a function on to a specific action.
|
||||
*
|
||||
* <code>
|
||||
* // Hooks a function "newLink" on to a "footer" action.
|
||||
* Action::add('footer', 'newLink', 10);
|
||||
*
|
||||
* function newLink() {
|
||||
* echo '<a href="#">My link</a>';
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @access public
|
||||
* @param string $action_name Action name
|
||||
* @param mixed $added_function Added function
|
||||
* @param integer $priority Priority. Default is 10
|
||||
* @param array $args Arguments
|
||||
*/
|
||||
public static function add($action_name, $added_function, $priority = 10, array $args = null)
|
||||
{
|
||||
// Hooks a function on to a specific action.
|
||||
static::$actions[] = array(
|
||||
'action_name' => (string) $action_name,
|
||||
'function' => $added_function,
|
||||
'priority' => (int) $priority,
|
||||
'args' => $args
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run functions hooked on a specific action hook.
|
||||
*
|
||||
* <code>
|
||||
* // Run functions hooked on a "footer" action hook.
|
||||
* Action::run('footer');
|
||||
* </code>
|
||||
*
|
||||
* @access public
|
||||
* @param string $action_name Action name
|
||||
* @param array $args Arguments
|
||||
* @param boolean $return Return data or not. Default is false
|
||||
* @return mixed
|
||||
*/
|
||||
public static function run($action_name, $args = [], $return = false)
|
||||
{
|
||||
// Redefine arguments
|
||||
$action_name = (string) $action_name;
|
||||
$return = (bool) $return;
|
||||
|
||||
// Run action
|
||||
if (count(static::$actions) > 0) {
|
||||
|
||||
// Sort actions by priority
|
||||
$actions = Arr::subvalSort(static::$actions, 'priority');
|
||||
|
||||
// Loop through $actions array
|
||||
foreach ($actions as $action) {
|
||||
|
||||
// Execute specific action
|
||||
if ($action['action_name'] == $action_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']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
102
monstra/Blocks.php
Executable file
102
monstra/Blocks.php
Executable file
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Monstra.
|
||||
*
|
||||
* (c) Romanenko Sergey / Awilum <awilum@msn.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
class Blocks
|
||||
{
|
||||
/**
|
||||
* An instance of the Blocks class
|
||||
*
|
||||
* @var object
|
||||
* @access protected
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* Protected clone method to enforce singleton behavior.
|
||||
*
|
||||
* @access protected
|
||||
*/
|
||||
protected function __clone()
|
||||
{
|
||||
// Nothing here.
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @access protected
|
||||
*/
|
||||
protected function __construct()
|
||||
{
|
||||
$blocks_cache_id = '';
|
||||
|
||||
$blocks = File::scan(STORAGE_PATH . '/blocks', 'md');
|
||||
|
||||
if ($blocks) {
|
||||
foreach ($blocks as $block) {
|
||||
$blocks_cache_id .= filemtime($block);
|
||||
}
|
||||
|
||||
// Create Unique Cache ID for Block
|
||||
$blocks_cache_id = md5('blocks' . ROOT_DIR . $blocks_cache_id);
|
||||
}
|
||||
|
||||
if (Cache::driver()->contains($blocks_cache_id)) {
|
||||
Cache::driver()->fetch($blocks_cache_id);
|
||||
} else {
|
||||
Config::set('site.pages.flush_cache', true);
|
||||
Cache::driver()->save($blocks_cache_id, $blocks_cache_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Page Block
|
||||
*
|
||||
* <code>
|
||||
* $block = Blocks::get('my-block');
|
||||
* </code>
|
||||
*
|
||||
* @access public
|
||||
* @param string $name Block name
|
||||
* @return string Formatted Block content
|
||||
*/
|
||||
public static function get($name)
|
||||
{
|
||||
if (File::exists($block_path = STORAGE_PATH .'/blocks/' . $name . '.md')) {
|
||||
|
||||
// Create Unique Cache ID for Block
|
||||
$block_cache_id = md5('block' . ROOT_DIR . $block_path . filemtime($block_path));
|
||||
|
||||
if (Cache::driver()->contains($block_cache_id)) {
|
||||
return Cache::driver()->fetch($block_cache_id);
|
||||
} else {
|
||||
Cache::driver()->save($block_cache_id, $block = Filter::apply('content', file_get_contents($block_path)));
|
||||
return $block;
|
||||
}
|
||||
} else {
|
||||
return 'Block '.$name.' is not found!';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Monstra Blocks
|
||||
*
|
||||
* <code>
|
||||
* Blocks::init();
|
||||
* </code>
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public static function init()
|
||||
{
|
||||
return !isset(self::$instance) and self::$instance = new Blocks();
|
||||
}
|
||||
}
|
248
monstra/Cache.php
Executable file
248
monstra/Cache.php
Executable file
@@ -0,0 +1,248 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Monstra.
|
||||
*
|
||||
* (c) Romanenko Sergey / Awilum <awilum@msn.com>
|
||||
*
|
||||
* 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') : 'Monstra') . '-' . md5(ROOT_DIR . Monstra::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
|
||||
!Dir::exists($cache_directory = CACHE_PATH . '/doctrine/') and Dir::create($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()
|
||||
{
|
||||
Dir::delete(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 Monstra Cache
|
||||
*
|
||||
* <code>
|
||||
* Cache::init();
|
||||
* </code>
|
||||
*
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public static function init()
|
||||
{
|
||||
return !isset(self::$instance) and self::$instance = new Cache();
|
||||
}
|
||||
}
|
113
monstra/Config.php
Executable file
113
monstra/Config.php
Executable file
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Monstra.
|
||||
*
|
||||
* (c) Romanenko Sergey / Awilum <awilum@msn.com>
|
||||
*
|
||||
* 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()
|
||||
{
|
||||
static::$config['site'] = Yaml::parseFile(CONFIG_PATH . '/' . 'site.yml');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set new or update existing config variable
|
||||
*
|
||||
* <code>
|
||||
* Config::set('site.title', 'value');
|
||||
* </code>
|
||||
*
|
||||
* @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
|
||||
*
|
||||
* <code>
|
||||
* Config::get('site');
|
||||
* Config::get('site.title');
|
||||
* Config::get('site.title', 'Default title');
|
||||
* </code>
|
||||
*
|
||||
* @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
|
||||
*
|
||||
* <code>
|
||||
* $config = Config::getConfig();
|
||||
* </code>
|
||||
*
|
||||
* @access public
|
||||
* @return array
|
||||
*/
|
||||
public static function getConfig()
|
||||
{
|
||||
return static::$config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Monstra Config
|
||||
*
|
||||
* <code>
|
||||
* Config::init();
|
||||
* </code>
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public static function init()
|
||||
{
|
||||
return !isset(self::$instance) and self::$instance = new Config();
|
||||
}
|
||||
}
|
120
monstra/Filter.php
Executable file
120
monstra/Filter.php
Executable file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Monstra.
|
||||
*
|
||||
* (c) Romanenko Sergey / Awilum <awilum@msn.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
class Filter
|
||||
{
|
||||
/**
|
||||
* Filters
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
protected static $filters = [];
|
||||
|
||||
/**
|
||||
* Protected constructor since this is a static class.
|
||||
*
|
||||
* @access protected
|
||||
*/
|
||||
protected function __construct()
|
||||
{
|
||||
// Nothing here
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply filters
|
||||
*
|
||||
* <code>
|
||||
* Filter::apply('content', $content);
|
||||
* </code>
|
||||
*
|
||||
* @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 apply($filter_name, $value)
|
||||
{
|
||||
// Redefine arguments
|
||||
$filter_name = (string) $filter_name;
|
||||
|
||||
$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
|
||||
*
|
||||
* <code>
|
||||
* Filter::add('content', 'replacer');
|
||||
*
|
||||
* function replacer($content) {
|
||||
* return preg_replace(array('/\[b\](.*?)\[\/b\]/ms'), array('<strong>\1</strong>'), $content);
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @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 add($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;
|
||||
}
|
||||
}
|
39
monstra/Markdown.php
Executable file
39
monstra/Markdown.php
Executable file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Monstra.
|
||||
*
|
||||
* (c) Romanenko Sergey / Awilum <awilum@msn.com>
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* <code>
|
||||
* $content = Markdown::parse($content);
|
||||
* </code>
|
||||
*
|
||||
* @access public
|
||||
* @param string $content Content to parse
|
||||
* @return string Formatted content
|
||||
*/
|
||||
public static function parse($content)
|
||||
{
|
||||
!static::$markdown and static::$markdown = new ParsedownExtra();
|
||||
|
||||
return static::$markdown->text($content);
|
||||
}
|
||||
}
|
98
monstra/Monstra.php
Executable file
98
monstra/Monstra.php
Executable file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Monstra
|
||||
*
|
||||
* @package Monstra
|
||||
* @author Romanenko Sergey / Awilum <awilum@msn.com>
|
||||
* @link http://monstra.org
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
class Monstra
|
||||
{
|
||||
/**
|
||||
* An instance of the Monstra class
|
||||
*
|
||||
* @var object
|
||||
* @access protected
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* The version of Monstra
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const VERSION = '4.0.0 alpha';
|
||||
|
||||
/**
|
||||
* Protected clone method to enforce singleton behavior.
|
||||
*
|
||||
* @access protected
|
||||
*/
|
||||
protected function __clone()
|
||||
{
|
||||
// Nothing here.
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @access protected
|
||||
*/
|
||||
protected function __construct()
|
||||
{
|
||||
// Init Config
|
||||
Config::init();
|
||||
|
||||
// Turn on output buffering
|
||||
ob_start();
|
||||
|
||||
// Display Errors
|
||||
Config::get('site.errors.display') and error_reporting(-1);
|
||||
|
||||
// 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 default timezone
|
||||
date_default_timezone_set(Config::get('site.timezone'));
|
||||
|
||||
// Start the session
|
||||
Session::start();
|
||||
|
||||
// Init Cache
|
||||
Cache::init();
|
||||
|
||||
// Init Plugins
|
||||
Plugins::init();
|
||||
|
||||
// Init Blocks
|
||||
Blocks::init();
|
||||
|
||||
// Init Pages
|
||||
Pages::init();
|
||||
|
||||
// Flush (send) the output buffer and turn off output buffering
|
||||
ob_end_flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Monstra Application
|
||||
*
|
||||
* <code>
|
||||
* Monstra::init();
|
||||
* </code>
|
||||
*
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public static function init()
|
||||
{
|
||||
return !isset(self::$instance) and self::$instance = new Monstra();
|
||||
}
|
||||
}
|
309
monstra/Pages.php
Executable file
309
monstra/Pages.php
Executable file
@@ -0,0 +1,309 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Monstra.
|
||||
*
|
||||
* (c) Romanenko Sergey / Awilum <awilum@msn.com>
|
||||
*
|
||||
* 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 Pages class
|
||||
*
|
||||
* @var object
|
||||
* @access protected
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* Current page.
|
||||
*
|
||||
* @var array
|
||||
* @access protected
|
||||
*/
|
||||
protected static $current_page;
|
||||
|
||||
/**
|
||||
* Current page template.
|
||||
*
|
||||
* @var object
|
||||
* @access protected
|
||||
*/
|
||||
protected static $current_template;
|
||||
|
||||
/**
|
||||
* Protected clone method to enforce singleton behavior.
|
||||
*
|
||||
* @access protected
|
||||
*/
|
||||
protected function __clone()
|
||||
{
|
||||
// Nothing here.
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @access protected
|
||||
*/
|
||||
protected function __construct()
|
||||
{
|
||||
// Get Current Page
|
||||
static::$current_page = static::getPage(Url::getUriString());
|
||||
|
||||
// Get Theme Templates
|
||||
static::$current_template = ((!empty(static::$current_page['template'])) ? static::$current_page['template'] : 'index');
|
||||
|
||||
// Send default header
|
||||
header('Content-Type: text/html; charset='.Config::get('site.charset'));
|
||||
|
||||
// Run actions before page rendered
|
||||
Action::run('before_page_rendered');
|
||||
|
||||
// Display page for current requested url
|
||||
static::display(static::$current_page);
|
||||
|
||||
// Run actions after page rendered
|
||||
Action::run('after_page_rendered');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get pages
|
||||
*
|
||||
* <code>
|
||||
* $pages = Pages::getPages('blog');
|
||||
* </code>
|
||||
*
|
||||
* @access public
|
||||
* @param string $url Url
|
||||
* @param string $order_by Order by
|
||||
* @param string $order_type Order type
|
||||
* @param array $ignore Pages to ignore
|
||||
* @param int $limit Limit of pages
|
||||
* @return array
|
||||
*/
|
||||
public static function getPages($url = '', $order_by = 'date', $order_type = 'DESC', $ignore = array('404'), $limit = null)
|
||||
{
|
||||
$pages = File::scan(STORAGE_PATH . '/pages/' . $url, 'md');
|
||||
|
||||
if ($pages) {
|
||||
foreach ($pages as $page) {
|
||||
$pages_cache_id .= filemtime($page);
|
||||
}
|
||||
|
||||
// Create Unique Cache ID for Pages
|
||||
$pages_cache_id = md5('pages' . ROOT_DIR . $url . $order_by . $order_type . implode(",", $ignore) . (($limit === null) ? 'null' : $limit) . $pages_cache_id);
|
||||
}
|
||||
|
||||
if (Cache::driver()->contains($pages_cache_id)) {
|
||||
return Cache::driver()->fetch($pages_cache_id);
|
||||
} else {
|
||||
foreach ($pages as $key => $page) {
|
||||
if (!in_array(basename($page, '.md'), $ignore)) {
|
||||
$content = file_get_contents($page);
|
||||
|
||||
$_page = explode('---', $content, 3);
|
||||
|
||||
$_pages[$key] = Yaml::parse($_page[1]);
|
||||
|
||||
$url = str_replace(STORAGE_PATH . '/pages', Url::getBase(), $page);
|
||||
$url = str_replace('index.md', '', $url);
|
||||
$url = str_replace('.md', '', $url);
|
||||
$url = str_replace('\\', '/', $url);
|
||||
$url = rtrim($url, '/');
|
||||
$_pages[$key]['url'] = $url;
|
||||
|
||||
$_content = $_page[2];
|
||||
|
||||
// Parse page for summary <!--more-->
|
||||
if (($pos = strpos($_content, "<!--more-->")) === false) {
|
||||
$_content = Filter::apply('content', $_content);
|
||||
} else {
|
||||
$_content = explode("<!--more-->", $_content);
|
||||
$_content['summary'] = Filter::apply('content', $_content[0]);
|
||||
$_content['content'] = Filter::apply('content', $_content[0].$_content[1]);
|
||||
}
|
||||
|
||||
if (is_array($_content)) {
|
||||
$_pages[$key]['summary'] = $_content['summary'];
|
||||
$_pages[$key]['content'] = $_content['content'];
|
||||
} else {
|
||||
$_pages[$key]['summary'] = $_content;
|
||||
$_pages[$key]['content'] = $_content;
|
||||
}
|
||||
|
||||
$_pages[$key]['slug'] = basename($page, '.md');
|
||||
}
|
||||
}
|
||||
|
||||
$_pages = Arr::subvalSort($_pages, $order_by, $order_type);
|
||||
|
||||
if ($limit != null) {
|
||||
$_pages = array_slice($_pages, null, $limit);
|
||||
}
|
||||
|
||||
Cache::driver()->save($pages_cache_id, $_pages);
|
||||
return $_pages;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get page
|
||||
*
|
||||
* <code>
|
||||
* $page = Pages::getPage('downloads');
|
||||
* </code>
|
||||
*
|
||||
* @access public
|
||||
* @param string $url Url
|
||||
* @return array
|
||||
*/
|
||||
public static function getPage($url)
|
||||
{
|
||||
|
||||
// If url is empty that its a homepage
|
||||
if ($url) {
|
||||
$file = STORAGE_PATH . '/pages/' . $url;
|
||||
} else {
|
||||
$file = STORAGE_PATH . '/pages/' . 'index';
|
||||
}
|
||||
|
||||
// Select the file
|
||||
if (is_dir($file)) {
|
||||
$file = STORAGE_PATH . '/pages/' . $url .'/index.md';
|
||||
} else {
|
||||
$file .= '.md';
|
||||
}
|
||||
|
||||
// Get 404 page if file not exists
|
||||
if (!file_exists($file)) {
|
||||
$file = STORAGE_PATH . '/pages/' . '404.md';
|
||||
Response::status(404);
|
||||
}
|
||||
|
||||
// Create Unique Cache ID for requested page
|
||||
$page_cache_id = md5('page' . ROOT_DIR . $file . filemtime($file));
|
||||
|
||||
if (Cache::driver()->contains($page_cache_id) && Config::get('site.pages.flush_cache') == false) {
|
||||
return Cache::driver()->fetch($page_cache_id);
|
||||
} else {
|
||||
$content = file_get_contents($file);
|
||||
|
||||
$_page = explode('---', $content, 3);
|
||||
|
||||
$page = Yaml::parse($_page[1]);
|
||||
|
||||
$url = str_replace(STORAGE_PATH . '/pages', Url::getBase(), $file);
|
||||
$url = str_replace('index.md', '', $url);
|
||||
$url = str_replace('.md', '', $url);
|
||||
$url = str_replace('\\', '/', $url);
|
||||
$url = rtrim($url, '/');
|
||||
$page['url'] = $url;
|
||||
|
||||
$_content = $_page[2];
|
||||
|
||||
// Parse page for summary <!--more-->
|
||||
if (($pos = strpos($_content, "<!--more-->")) === false) {
|
||||
$_content = Filter::apply('content', $_content);
|
||||
} else {
|
||||
$_content = explode("<!--more-->", $_content);
|
||||
$_content['summary'] = Filter::apply('content', $_content[0]);
|
||||
$_content['content'] = Filter::apply('content', $_content[0].$_content[1]);
|
||||
}
|
||||
|
||||
if (is_array($_content)) {
|
||||
$page['summary'] = $_content['summary'];
|
||||
$page['content'] = $_content['content'];
|
||||
} else {
|
||||
$page['content'] = $_content;
|
||||
}
|
||||
|
||||
$page['slug'] = basename($file, '.md');
|
||||
|
||||
// Overload page title, keywords and description if needed
|
||||
empty($page['title']) and $page['title'] = Config::get('site.title');
|
||||
empty($page['keywords']) and $page['keywords'] = Config::get('site.keywords');
|
||||
empty($page['description']) and $page['description'] = Config::get('site.description');
|
||||
|
||||
Cache::driver()->save($page_cache_id, $page);
|
||||
return $page;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Current Page
|
||||
*
|
||||
* <code>
|
||||
* $page = Pages::getCurrentPage();
|
||||
* </code>
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getCurrentPage()
|
||||
{
|
||||
return static::$current_page;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Current Page
|
||||
*
|
||||
* <code>
|
||||
* Pages::updateCurrentPage('title', 'My new Page Title');
|
||||
* </code>
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function updateCurrentPage($path, $value)
|
||||
{
|
||||
Arr::set(static::$current_page, $path, $value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Display Page
|
||||
*
|
||||
* <code>
|
||||
* Pages::display($page);
|
||||
* </code>
|
||||
*
|
||||
* @access public
|
||||
* @param array $page Page array
|
||||
* @return string
|
||||
*/
|
||||
public static function display($page)
|
||||
{
|
||||
Theme::getTemplate(((!empty($page['template'])) ? $page['template'] : 'index'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Current Template
|
||||
*
|
||||
* <code>
|
||||
* $template = Pages::getCurrentTemplate();
|
||||
* </code>
|
||||
*
|
||||
* @access public
|
||||
* @return object
|
||||
*/
|
||||
public static function getCurrentTemplate()
|
||||
{
|
||||
return static::$current_template;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Monstra Pages
|
||||
*
|
||||
* <code>
|
||||
* Pages::init();
|
||||
* </code>
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public static function init()
|
||||
{
|
||||
return !isset(self::$instance) and self::$instance = new Pages();
|
||||
}
|
||||
}
|
116
monstra/Plugins.php
Executable file
116
monstra/Plugins.php
Executable file
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Monstra.
|
||||
*
|
||||
* (c) Romanenko Sergey / Awilum <awilum@msn.com>
|
||||
*
|
||||
* 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 Plugins class
|
||||
*
|
||||
* @var object
|
||||
* @access protected
|
||||
*/
|
||||
protected static $instance = null;
|
||||
|
||||
/**
|
||||
* Protected clone method to enforce singleton behavior.
|
||||
*
|
||||
* @access protected
|
||||
*/
|
||||
protected function __clone()
|
||||
{
|
||||
// Nothing here.
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @access protected
|
||||
*/
|
||||
protected function __construct()
|
||||
{
|
||||
$plugins_cache_id = '';
|
||||
|
||||
$plugin_manifest = [];
|
||||
$plugin_settings = [];
|
||||
|
||||
// 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 (File::exists($_plugin = PLUGINS_PATH . '/' . $plugin . '/' . $plugin . '.yml')) {
|
||||
$plugins_cache_id .= filemtime($_plugin);
|
||||
}
|
||||
}
|
||||
|
||||
// Create Unique Cache ID for Plugins
|
||||
$plugins_cache_id = md5('plugins' . ROOT_DIR . 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 (File::exists($_plugin_manifest = PLUGINS_PATH . '/' . $plugin . '/' . $plugin . '.yml')) {
|
||||
$plugin_manifest = Yaml::parseFile($_plugin_manifest);
|
||||
}
|
||||
|
||||
if (File::exists($_plugin_settings = PLUGINS_PATH . '/' . $plugin . '/settings.yml')) {
|
||||
$plugin_settings = Yaml::parseFile($_plugin_settings);
|
||||
}
|
||||
|
||||
$_plugins_config[File::name($_plugin_manifest)] = array_merge($plugin_manifest, $plugin_settings);
|
||||
}
|
||||
|
||||
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';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Run Actions on plugins_loaded
|
||||
Action::run('plugins_loaded');
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Monstra Plugins
|
||||
*
|
||||
* <code>
|
||||
* Plugins::init();
|
||||
* </code>
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public static function init()
|
||||
{
|
||||
if (! isset(self::$instance)) {
|
||||
self::$instance = new Plugins();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
}
|
9
monstra/Theme.php
Executable file
9
monstra/Theme.php
Executable file
@@ -0,0 +1,9 @@
|
||||
<?php
|
||||
|
||||
class Theme
|
||||
{
|
||||
public static function getTemplate($template = null)
|
||||
{
|
||||
include THEMES_PATH . '/' . Config::get('site.theme') . '/' . $template . '.php';
|
||||
}
|
||||
}
|
59
monstra/Yaml.php
Executable file
59
monstra/Yaml.php
Executable file
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Monstra.
|
||||
*
|
||||
* (c) Romanenko Sergey / Awilum <awilum@msn.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
class Yaml
|
||||
{
|
||||
/**
|
||||
* Parses YAML to array.
|
||||
*
|
||||
* <code>
|
||||
* $array = Yaml::parseFile('file.yml');
|
||||
* </code>
|
||||
*
|
||||
* @access public
|
||||
* @param string $file Path to YAML file.
|
||||
* @return array
|
||||
*/
|
||||
public static function parseFile($file)
|
||||
{
|
||||
return Spyc::YAMLLoad($file);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses YAML to array.
|
||||
*
|
||||
* <code>
|
||||
* $array = Yaml::parse('title: My title');
|
||||
* </code>
|
||||
*
|
||||
* @param string $string YAML string.
|
||||
* @return array
|
||||
*/
|
||||
public static function parse($string)
|
||||
{
|
||||
return Spyc::YAMLLoadString($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps array to YAML.
|
||||
*
|
||||
* <code>
|
||||
* $yaml = Yaml::dump($data);
|
||||
* </code>
|
||||
*
|
||||
* @param array $data Array.
|
||||
* @return string
|
||||
*/
|
||||
public static function dump($data)
|
||||
{
|
||||
return Spyc::YAMLDump($data, false, false, true);
|
||||
}
|
||||
}
|
15
monstra/boot/actions.php
Executable file
15
monstra/boot/actions.php
Executable file
@@ -0,0 +1,15 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Monstra.
|
||||
*
|
||||
* (c) Romanenko Sergey / Awilum <awilum@msn.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
// Set Monstra Meta Generator
|
||||
Action::add('theme_meta', function () {
|
||||
echo('<meta name="generator" content="Powered by Monstra" />');
|
||||
});
|
34
monstra/boot/defines.php
Executable file
34
monstra/boot/defines.php
Executable file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Monstra.
|
||||
*
|
||||
* (c) Romanenko Sergey / Awilum <awilum@msn.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
// Define the path to the root directory (without trailing slash).
|
||||
define('ROOT_DIR', str_replace(DIRECTORY_SEPARATOR, '/', getcwd()));
|
||||
|
||||
// Define the path to the storage directory (without trailing slash).
|
||||
define('SITE_PATH', ROOT_DIR . '/site');
|
||||
|
||||
// Define the path to the storage directory (without trailing slash).
|
||||
define('STORAGE_PATH', SITE_PATH . '/storage');
|
||||
|
||||
// Define the path to the themes directory (without trailing slash).
|
||||
define('THEMES_PATH', SITE_PATH . '/themes');
|
||||
|
||||
// Define the path to the plugins directory (without trailing slash).
|
||||
define('PLUGINS_PATH', SITE_PATH . '/plugins');
|
||||
|
||||
// Define the path to the config directory (without trailing slash).
|
||||
define('CONFIG_PATH', SITE_PATH . '/config');
|
||||
|
||||
// Define the path to the cache directory (without trailing slash).
|
||||
define('CACHE_PATH', SITE_PATH . '/cache');
|
||||
|
||||
// Define the path to the cache directory (without trailing slash).
|
||||
define('ACCOUNTS_PATH', SITE_PATH . '/cache');
|
16
monstra/boot/filters.php
Executable file
16
monstra/boot/filters.php
Executable file
@@ -0,0 +1,16 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Monstra.
|
||||
*
|
||||
* (c) Romanenko Sergey / Awilum <awilum@msn.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
// Add Shortcode parser filter
|
||||
Filter::add('content', 'Shortcode::parse', 1);
|
||||
|
||||
// Add Parsedown parser filter
|
||||
Filter::add('content', 'Markdown::parse', 2);
|
22
monstra/boot/shortcodes.php
Executable file
22
monstra/boot/shortcodes.php
Executable file
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of the Monstra.
|
||||
*
|
||||
* (c) Romanenko Sergey / Awilum <awilum@msn.com>
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
// Add {block name=block-name} shortcode
|
||||
Shortcode::add('block', function ($attributes) {
|
||||
if (isset($attributes['name'])) {
|
||||
return Blocks::get($attributes['name']);
|
||||
}
|
||||
});
|
||||
|
||||
// Add {site_url} shortcode
|
||||
Shortcode::add('site_url', function () {
|
||||
return Url::getBase();
|
||||
});
|
Reference in New Issue
Block a user