1
0
mirror of https://github.com/flextype/flextype.git synced 2025-08-18 02:41:27 +02:00

Merge branch 'dev'

This commit is contained in:
Awilum
2019-06-14 19:17:50 +03:00
243 changed files with 14777 additions and 7836 deletions

12
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,12 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: awilum
open_collective: # Replace with a single Open Collective username
ko_fi: awilum
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: https://qiwi.com/p/79805359141

1
.gitignore vendored
View File

@@ -1,5 +1,6 @@
# Composer
.composer
composer.lock
vendor/*
!*/vendor/*

View File

@@ -1,8 +1,8 @@
##
# @package Flextype
#
# @author Sergey Romanenko <awilum@yandex.ru>
# @link http://flextype.org
# @author Sergey Romanenko <hello@romanenko.digital>
# @link http://romanenko.digital
#
# For the full copyright and license information, please view the LICENSE
# file that was distributed with this source code.

View File

@@ -1,3 +1,54 @@
## [0.9.0] - 2019-06-14
### Added
- Flextype Core: Slim Framework Integration!
- Flextype Core: Twig Template Engine Integration!
- Flextype Core: Whoops Error Handler Integration!
- Flextype Core: Monolog library Integration!
- Flextype Core: Slugify library Integration!
- Flextype Core: Complete Glide/Intervention Image Implemented for Image manipulation on fly!
- Flextype Core: New Event handler from The League of Extraordinary Packages for better event handling.
- Flextype Core: New Entries API
- Flextype Core: New Fieldsets API
- Flextype Core: New Snippets API
- Flextype Core: New Plugins API
- Flextype Core: New JSON Parser instead of old YAML Parser.
- Flextype Core: Using new languages files format and JSON extension instead of YAML.
- Flextype Core: Using JSON extension instead of YAML for all kind of data to store.
- Flextype Core: New CSRF service for better cross-site request forgery protection.
- Flextype Core: composer.json ext-json and ext-mbstring added into require section.
- Flextype Core: composer.json suggest section added.
- Flextype Core: composer.json: apcu-autoloader added for APCu cache as a fallback for the class map.
- Flextype Site: New plugin Site added.
- Flextype Core: Respect Validation - The most awesome validation engine ever created for PHP - added.
- Flextype Admin Panel: New admin panel plugin based on Slim Framework.
- Flextype Admin Panel: Fieldset Sections(groups) added.
- Flextype Admin Panel: New Field types - select, editor (instead of html)
### Changed
- Flextype Core: Thunderer Shortcodes don't parse fields by default, need to use filter.
- Flextype Core: Thunderer Shortcodes updated to 0.7.2.
- Flextype Core: Flextype Components Arr updated to 1.2.5
- Flextype Core: Flextype Components Number updated to 1.1.0
- Admin Panel: Bootstrap updated to 4.3.1
- Admin Panel: Codemirror updated to 5.43.0
- Admin Panel: Trumbowyg updated to 2.18.0
- Admin Panel: Settings Manager - locales list - improvements!
### Fixed
- Admin Panel: Translates fixes.
- Admin Panel: Issue with js error for codemirror - fixed.
- Flextype Core: Plugins API - issue with plugins list fixed.
### Removed
- Flextype Admin Panel: Menus Manager removed.
- Flextype Core: YAML Parser removed.
- Flextype Core: Symfony YAML Component removed.
- Flextype Core: Flextype Token Component removed.
- Flextype Core: Flextype Notification Component removed.
- Flextype Core: Flextype Error Handler Component removed.
- Flextype Core: Flextype Event Component removed.
## [0.8.3] - 2019-01-16
### Added
- Admin Panel: New Gorgeous Light Theme for Admin panel!

View File

@@ -7,3 +7,4 @@ Flextype is an open source project and community contributions are essential to
* Find and [report issues.](https://github.com/flextype/flextype/issues)
* Link back to [Flextype](http://flextype.org).
* [Donate to keep Flextype free.](http://flextype.org/about/sponsors)
* [Join Flextype International Translator Team](https://crowdin.com/project/flextype/invite)

View File

@@ -1,10 +1,13 @@
# Flextype
[![Discord](https://img.shields.io/discord/423097982498635778.svg?logo=discord&colorB=728ADA&label=Discord%20Chat&style=flat-square)](https://discordapp.com/invite/CCKPKVG)
![Version](https://img.shields.io/badge/version-0.8.3-brightgreen.svg?style=flat-square)
![MIT License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)
![preview](/site/plugins/admin/preview.png)
<p align="center">
<a href="https://github.com/flextype/flextype/releases"><img alt="Version" src="https://img.shields.io/github/release/flextype/flextype.svg?label=version"></a> <a href="https://github.com/flextype/flextype"><img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License"></a> <a href="https://github.com/flextype/flextype"><img src="https://img.shields.io/github/downloads/flextype/flextype/total.svg?colorB=blue" alt="Total downloads"></a> <a href="https://crowdin.com/project/flextype"><img src="https://d322cqt584bo4o.cloudfront.net/flextype/localized.svg" alt="Crowdin"></a> <a href="https://scrutinizer-ci.com/g/flextype/flextype?branch=master"><img src="https://img.shields.io/scrutinizer/g/flextype/flextype.svg?branch=master" alt="Quality Score"></a> <a href="https://discordapp.com/invite/CCKPKVG"><img src="https://img.shields.io/discord/423097982498635778.svg?logo=discord&colorB=728ADA&label=Discord%20Chat" alt="Discord"></a>
</p>
# Flextype
Flextype is 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!
@@ -41,8 +44,11 @@ Make sure your server meets the following requirements.
#### PHP extensions
Flextype needs the following PHP extensions to be enabled:
- Multibyte String
- SPL
- PHP [mbstring](http://php.net/manual/en/book.mbstring.php) module for full UTF-8 support.
- PHP [gd](http://php.net/manual/en/book.image.php) module for image processing.
- PHP [json](https://php.net/manual/en/book.json.php) module for JSON manipulation.
- PHP [Fileinfo](https://www.php.net/manual/en/book.fileinfo.php)
- PHP [SPL](https://www.php.net/manual/en/book.spl.php)
Although it is optional, we strongly recommend enabling the following PHP extensions:
APC, APCu, XCache, Memcached, or Redis for better performance.
@@ -64,7 +70,7 @@ Mobile
#### Using (S)FTP
[Download the latest version.](http://flextype.org/download)
[Download the latest version.](http://flextype.org/en/downloads)
Unzip the contents to a new folder on your local computer, and upload to your webhost using the (S)FTP client of your choice. After youve done this, be sure to chmod the following directories (with containing files) to 755(or 777), so they are readable and writable by Flextype:
* `site/`
@@ -77,16 +83,20 @@ You can easily install Flextype with Composer.
composer create-project flextype/flextype
```
Install vendor libs for Flextype
```
composer install
```
Install vendor libs for Default Theme
```
composer install
cd site/themes/default
npm install
gulp
```
Install vendor libs for Admin Panel
Install vendor libs for Admin Panel plugin
```
cd site/plugins/admin
@@ -95,6 +105,15 @@ npm install
gulp
```
Install vendor libs for Site plugin
```
cd site/plugins/site
composer install
npm install
gulp
```
## COMMUNITY
Flextype is open source, community driven project, and maintained by community!
@@ -120,17 +139,18 @@ With Flextype you can create any project you want.
## CONTRIBUTE
Flextype is an open source project and community contributions are essential to its growing and success. Contributing to the Flextype is easy and you can give as little or as much time as you want.
* Help on the [Communities.](http://flextype.org/documentation/basics/getting-help)
* Help on the [Communities.](http://flextype.org/en/documentation/guide/basics/getting-help)
* Develop a new plugin.
* Create a new theme.
* Find and [report issues.](https://github.com/flextype/flextype/issues)
* Link back to [Flextype](http://flextype.org).
* [Donate to keep Flextype free.](http://flextype.org/about/sponsors)
* [Donate to keep Flextype free.](http://flextype.org/en/about/sponsors)
* [Join Flextype International Translator Team](https://crowdin.com/project/flextype/invite)
## LINKS
- [Site](http://flextype.org)
- [Documentation](http://flextype.org/documentation)
- [Documentation](http://flextype.org/en/documentation)
## LICENSE

View File

@@ -1,15 +1,15 @@
{
"name": "flextype/flextype",
"type": "project",
"description": "Modern Open Source Flat-File Content Management System",
"description": "Build fast, flexible, easier to manage websites with Flextype.",
"keywords": ["flextype", "php", "cms", "flat-file cms", "flat cms", "flatfile cms", "html"],
"homepage": "http://flextype.org",
"license": "MIT",
"authors": [
{
"name": "Sergey Romanenko",
"email": "awilum@yandex.ru",
"homepage": "https://github.com/Awilum"
"email": "hello@romanenko.digital",
"homepage": "http://romanenko.digital"
}
],
"support": {
@@ -17,29 +17,51 @@
},
"require": {
"php": ">=7.1.3",
"doctrine/cache": "1.8.0",
"symfony/yaml": "4.2.2",
"thunderer/shortcode": "0.7.0",
"flextype-components/arr" : "1.2.4",
"flextype-components/assets" : "1.0.1",
"ext-json": "*",
"ext-mbstring": "*",
"doctrine/cache": "^1.8.0",
"thunderer/shortcode": "^0.7.2",
"flextype-components/arr" : "1.2.5",
"flextype-components/assets" : "1.0.3",
"flextype-components/cookie" : "1.2.0",
"flextype-components/date" : "1.0.0",
"flextype-components/debug" : "1.0.0",
"flextype-components/event" : "1.0.4",
"flextype-components/errorhandler" : "1.0.5",
"flextype-components/filesystem" : "1.1.5",
"flextype-components/form" : "1.0.2",
"flextype-components/filesystem" : "2.0.3",
"flextype-components/i18n" : "1.2.0",
"flextype-components/http" : "1.1.1",
"flextype-components/html" : "1.0.0",
"flextype-components/number" : "1.0.0",
"flextype-components/notification" : "1.0.1",
"flextype-components/registry" : "1.1.0",
"flextype-components/number" : "1.1.0",
"flextype-components/registry" : "2.0.0",
"flextype-components/session" : "1.1.1",
"flextype-components/token" : "1.2.0",
"flextype-components/view" : "1.1.1",
"flextype-components/text" : "1.1.2",
"league/glide": "^1.4"
"flextype-components/form" : "1.0.2",
"slim/slim": "^3.0",
"slim/twig-view": "^2.5",
"slim/flash": "^0.4.0",
"slim/csrf": "^0.8.3",
"zeuxisoo/slim-whoops": "^0.6.0",
"league/glide-slim": "^1.0",
"league/event": "^2.2",
"league/glide": "^1.5",
"respect/validation": "^1.0",
"monolog/monolog": "^1.24",
"cocur/slugify": "^3.2",
"oscarotero/psr7-middlewares": "^3.21"
},
"suggest": {
"ext-zend-opcache": "Recommended for better performance",
"ext-memcache": "Needed to support Memcache servers",
"ext-memcached": "Needed to support Memcached servers",
"ext-redis": "Needed to support Redis servers"
},
"config": {
"apcu-autoloader": true,
"platform": {
"php": "7.1.3"
}
},
"autoload": {
"classmap": [

3
crowdin.yml Normal file
View File

@@ -0,0 +1,3 @@
files:
- source: /site/plugins/admin/lang/en_US.json
translation: /site/plugins/admin/lang/%locale_with_underscore%.json

View File

@@ -1,365 +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 Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Registry\Registry;
use \Doctrine\Common\Cache as DoctrineCache;
class Cache
{
/**
* An instance of the Cache class
*
* @var object
* @access private
*/
private 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;
/**
* Private clone method to enforce singleton behavior.
*
* @access private
*/
private function __clone()
{
}
/**
* Private wakeup method to enforce singleton behavior.
*
* @access private
*/
private function __wakeup()
{
}
/**
* Private construct method to enforce singleton behavior.
*
* @access private
*/
private function __construct()
{
Cache::init();
}
/**
* Init Cache
*
* @access protected
* @return void
*/
protected static function init() : void
{
// Create Cache Directory
!Filesystem::dirExists(PATH['cache']) and Filesystem::createDir(PATH['cache']);
// Set current time
Cache::$now = time();
// Create cache key to allow invalidate all cache on configuration changes.
Cache::$key = (Registry::get('settings.cache.prefix') ?? 'flextype') . '-' . md5(PATH['site'] . Flextype::VERSION);
// Get Cache Driver
Cache::$driver = Cache::getCacheDriver();
// Set the cache namespace to our unique key
Cache::$driver->setNamespace(Cache::$key);
}
/**
* Get Cache Driver
*
* @access public
* @return object
*/
public static function getCacheDriver()
{
$driver_name = Registry::get('settings.cache.driver');
$cache_directory = PATH['cache'] . '/doctrine/';
if (!$driver_name || $driver_name == 'auto') {
if (extension_loaded('apcu')) {
$driver_name = 'apcu';
} elseif (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) {
// The ApcCache driver uses the apc_fetch, apc_exists, etc. functions
// that come with PHP so no additional setup is required in order to use it.
case 'apc':
$driver = new DoctrineCache\ApcCache();
break;
// The ApcuCache driver uses the apcu_fetch, apcu_exists, etc. functions
// that come with PHP so no additional setup is required in order to use it.
case 'apcu':
$driver = new DoctrineCache\ApcuCache();
break;
// The ArrayCache driver stores the cache data in PHPs memory and is not persisted anywhere.
// This can be useful for caching things in memory for a single process when you don't need the cache to be persistent across processes.
case 'array':
$driver = new DoctrineCache\ArrayCache();
break;
// The WinCacheCache driver uses the wincache_ucache_get, wincache_ucache_exists, etc. functions
// that come with the wincache extension
// http://php.net/manual/en/book.wincache.php
case 'wincache':
$driver = new DoctrineCache\WinCacheCache();
break;
// The XcacheCache driver uses functions that come with the xcache extension
// https://xcache.lighttpd.net
case 'xcache':
$driver = new DoctrineCache\XcacheCache();
break;
// The MemcacheCache drivers stores the cache data in Memcache.
case 'memcache':
$memcache = new \Memcache();
$memcache->connect(
Registry::get('settings.cache.memcache.server', 'localhost'),
Registry::get('settings.cache.memcache.port', 11211)
);
$driver = new DoctrineCache\MemcacheCache();
$driver->setMemcache($memcache);
break;
// The MemcachedCache drivers stores the cache data in Memcached.
case 'memcached':
$memcached = new \Memcached();
$memcached->addServer(
Registry::get('settings.cache.memcached.server', 'localhost'),
Registry::get('settings.cache.memcache.port', 11211)
);
$driver = new DoctrineCache\MemcachedCache();
$driver->setMemcached($memcached);
break;
// The SQLite3Cache driver stores the cache data in a SQLite database and depends on the sqlite3 extension
// http://php.net/manual/en/book.sqlite3.php
case 'sqlite3':
// Create doctrine cache directory if its not exists
!Filesystem::fileExists($cache_directory) and Filesystem::createDir($cache_directory);
$db = new \SQLite3($cache_directory . Registry::get('settings.cache.sqlite3.database', 'flextype') . '.db');
$driver = new DoctrineCache\SQLite3Cache($db, Registry::get('settings.cache.sqlite3.table', 'flextype'));
break;
// The ZendDataCache driver uses the Zend Data Cache API available in the Zend Platform.
case 'zend':
$driver = new DoctrineCache\ZendDataCache();
break;
// The RedisCache driver stores the cache data in Redis and depends on the phpredis extension
// https://github.com/phpredis/phpredis
case 'redis':
$redis = new \Redis();
$socket = Registry::get('settings.cache.redis.socket', false);
$password = Registry::get('settings.cache.redis.password', false);
if ($socket) {
$redis->connect($socket);
} else {
$redis->connect(
Registry::get('settings.cache.redis.server', 'localhost'),
Registry::get('settings.cache.redis.port', 6379)
);
}
// Authenticate with password if set
if ($password && !$redis->auth($password)) {
throw new \RedisException('Redis authentication failed');
}
$driver = new DoctrineCache\RedisCache();
$driver->setRedis($redis);
break;
default:
// Create doctrine cache directory if its not exists
!Filesystem::fileExists($cache_directory) and Filesystem::createDir($cache_directory);
$driver = new DoctrineCache\FilesystemCache($cache_directory);
break;
}
return $driver;
}
/**
* Returns driver variable
*
* @access public
* @return object
*/
public static function driver()
{
return Cache::$driver;
}
/**
* Get cache key.
*
* @access public
* @return string
*/
public static function getKey() : string
{
return Cache::$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 static function fetch(string $id)
{
if (Registry::get('settings.cache.enabled')) {
return Cache::$driver->fetch($id);
} else {
return false;
}
}
/**
* Returns a boolean state of whether or not the item exists in the cache based on id key
*
* @param string $id the id of the cached data entry
* @return bool true if the cached items exists
*/
public static function contains($id)
{
if (Registry::get('settings.cache.enabled')) {
return Cache::$driver->contains(($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 static function save(string $id, $data, $lifetime = null)
{
if (Registry::get('settings.cache.enabled')) {
if ($lifetime === null) {
$lifetime = Cache::getLifetime();
}
Cache::$driver->save($id, $data, $lifetime);
}
}
/**
* Clear Cache
*/
public static function clear() : void
{
// Clear stat cache
@clearstatcache();
// Clear opcache
function_exists('opcache_reset') and @opcache_reset();
// Remove cache dirs
Filesystem::deleteDir(PATH['cache'] . '/doctrine/');
Filesystem::deleteDir(PATH['cache'] . '/glide/');
}
/**
* Set the cache lifetime.
*
* @access public
* @param int $future timestamp
*/
public static function setLifetime(int $future)
{
if (!$future) {
return;
}
$interval = $future - Cache::$now;
if ($interval > 0 && $interval < Cache::getLifetime()) {
Cache::$lifetime = $interval;
}
}
/**
* Retrieve the cache lifetime (in seconds)
*
* @access public
* @return mixed
*/
public static function getLifetime()
{
if (Cache::$lifetime === null) {
Cache::$lifetime = Registry::get('settings.cache.lifetime') ?: 604800;
}
return Cache::$lifetime;
}
/**
* Get the Cache instance.
*
* @access public
* @return object
*/
public static function getInstance()
{
if (is_null(Cache::$instance)) {
Cache::$instance = new self;
}
return Cache::$instance;
}
}

View File

@@ -1,500 +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 Flextype\Component\Arr\Arr;
use Flextype\Component\Http\Http;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Event\Event;
use Flextype\Component\Registry\Registry;
use Thunder\Shortcode\ShortcodeFacade;
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
class Entries
{
/**
* An instance of the Entry class
*
* @var object
* @access private
*/
private static $instance = null;
/**
* Shortcode object
*
* @var object
* @access private
*/
private static $shortcode = null;
/**
* Current entry data array
*
* @var array
* @access private
*/
private static $entry = [];
/**
* Private clone method to enforce singleton behavior.
*
* @access private
*/
private function __clone()
{
}
/**
* Private wakeup method to enforce singleton behavior.
*
* @access private
*/
private function __wakeup()
{
}
/**
* Private construct method to enforce singleton behavior.
*
* @access private
*/
private function __construct()
{
Entries::init();
}
/**
* Init Entry
*
* @access private
* @return void
*/
private static function init() : void
{
Entries::processCurrentEntry();
}
/**
* Process Current Entry
*
* @access private
* @return void
*/
private static function processCurrentEntry() : void
{
// Event: The entry is not processed and not sent to the display.
Event::dispatch('onCurrentEntryBeforeProcessed');
// Init Parsers
Entries::initParsers();
// Event: The entry has been not loaded.
Event::dispatch('onCurrentEntryBeforeLoaded');
// Set current requested entry data to global $entry array
Entries::$entry = Entries::getEntry(Http::getUriString());
// Event: The entry has been fully processed and not sent to the display.
Event::dispatch('onCurrentEntryBeforeDisplayed');
// Display entry for current requested url
Entries::displayCurrentEntry();
// Event: The entry has been fully processed and sent to the display.
Event::dispatch('onCurrentEntryAfterProcessed');
}
/**
* Get current entry
*
* $entry = Entries::getCurrentPage();
*
* @access public
* @return array
*/
public static function getCurrentEntry() : array
{
return Entries::$entry;
}
/**
* Update current entry
*
* Entries::updateCurrentPage('title', 'New entry title');
*
* @access public
* @param string $path Array path
* @param mixed $value Value to set
* @return void
*/
public static function updateCurrentEntry(string $path, $value) : void
{
Arr::set(Entries::$entry, $path, $value);
}
/**
* Get entry
*
* $entry = Entries::getEntry('projects');
*
* @access public
* @param string $url Page url.
* @param bool $raw Parse content or raw content without parsing.
* @param bool $hidden Get hidden entries.
* @return array|string
*/
public static function getEntry(string $url = '', bool $raw = false, bool $hidden = false)
{
// If $url is empty then set path for default main entry
if ($url === '') {
$file_path = PATH['entries'] . '/' . Registry::get('settings.entries.main') . '/entry.html';
} else {
$file_path = PATH['entries'] . '/' . $url . '/entry.html';
}
// If entry exist
if (Filesystem::fileExists($file_path)) {
$entry_cache_id = md5('entry' . $file_path . filemtime($file_path) . (($raw === true) ? 'true' : 'false') . (($hidden === true) ? 'true' : 'false'));
// Try to get the entry from cache
if (Cache::contains($entry_cache_id)) {
return Cache::fetch($entry_cache_id);
} else {
// Get raw entry if $raw is true
if ($raw) {
$entry = Entries::processEntry($file_path, true);
} else {
$entry = Entries::processEntry($file_path);
// Don't proccess 404 entry if we want to get hidden entry.
if ($hidden === false) {
// Get 404 entry if entry is not published
if (isset($entry['visibility']) && ($entry['visibility'] === 'draft' || $entry['visibility'] === 'hidden')) {
$entry = Entries::getError404Entry();
}
}
}
Cache::save($entry_cache_id, $entry);
return $entry;
}
} else {
return Entries::getError404Entry();
}
}
/**
* Get entries
*
* // Get list of subentries for entry 'projects'
* $entries = Entries::getEntries('projects');
*
* // Get list of subentries for entry 'projects' and order by date and order type DESC
* $entries = Entries::getEntries('projects', false, 'date', 'DESC');
*
* @access public
* @param string $url Page url.
* @param string $order_by Order by specific entry field.
* @param string $order_type Order type: DESC or ASC
* @param int $offset Offset
* @param int $length Length
* @param bool $multilevel Get nested entries or not.
* @param bool $raw Parse content or raw content without parsing.
* @return array
*/
public static function getEntries(string $url = '', string $order_by = 'date', string $order_type = 'DESC', int $offset = null, int $length = null, bool $multilevel = false, bool $raw = false) : array
{
// if $url is empty then set path for defined main entry
if ($url === '') {
$file_path = PATH['entries'] . '/';
} else {
$file_path = PATH['entries'] . '/' . $url;
}
// Pages array where founded entries will stored
$entries = [];
// Pages cache id
$entry_cache_id = '';
// Get entries for $url
// If $url is empty then we want to have a list of entries for /entries dir.
if ($url === '') {
// Get entries list
$entries_list = Filesystem::getFilesList($file_path, 'html', true, $multilevel);
// Create entries cached id
foreach ($entries_list as $key => $entry) {
$entry_cache_id .= md5('entries' . $entry . filemtime($entry) . (($raw === true) ? 'true' : 'false') . $order_by . $order_type . $offset . $length);
}
if (Cache::contains($entry_cache_id)) {
$entries = Cache::fetch($entry_cache_id);
} else {
// Create entries array from entries list
foreach ($entries_list as $key => $entry) {
$entries[$key] = Entries::processEntry($entry, $raw);
}
Cache::save($entry_cache_id, $entries);
}
} else {
// Get entries list
$entries_list = Filesystem::getFilesList($file_path, 'html', true, $multilevel);
// Create entries cached id
foreach ($entries_list as $key => $entry) {
if (strpos($entry, $url . '/entry.html') !== false) {
// ignore ...
} else {
$entry_cache_id .= md5('entries' . $entry . filemtime($entry) . (($raw === true) ? 'true' : 'false') . $order_by . $order_type . $offset . $length);
}
}
if (Cache::contains($entry_cache_id)) {
$entries = Cache::fetch($entry_cache_id);
} else {
// Create entries array from entries list and ignore current requested entry
foreach ($entries_list as $key => $entry) {
if (strpos($entry, $url . '/entry.html') !== false) {
// ignore ...
} else {
$entries[$key] = Entries::processEntry($entry, $raw);
}
}
Cache::save($entry_cache_id, $entries);
}
}
// Sort and Slice entries if $raw === false
if (count($entries) > 0) {
if (!$raw) {
$entries = Arr::sort($entries, $order_by, $order_type);
if ($offset !== null && $length !== null) {
$entries = array_slice($entries, $offset, $length);
}
}
}
// Return entries array
return $entries;
}
/**
* Get Error404 entry
*
* @return array
*/
private static function getError404Entry() : array
{
Http::setResponseStatus(404);
$entry['title'] = Registry::get('settings.entries.error404.title');
$entry['description'] = Registry::get('settings.entries.error404.description');
$entry['content'] = Registry::get('settings.entries.error404.content');
$entry['template'] = Registry::get('settings.entries.error404.template');
return $entry;
}
/**
* Returns $shortcode object
*
* @access public
* @return object
*/
public static function shortcode() : ShortcodeFacade
{
return Entries::$shortcode;
}
/**
* Front matter parser
*
* $content = Entries::frontMatterParser($content);
*
* @param string $content Content to parse
* @access public
* @return array
*/
public static function frontMatterParser(string $content) : array
{
$parts = preg_split('/^[\s\r\n]?---[\s\r\n]?$/sm', PHP_EOL.ltrim($content));
if (count($parts) < 3) return ['matter' => [], 'body' => $content];
return ['matter' => trim($parts[1]), 'body' => implode(PHP_EOL.'---'.PHP_EOL, array_slice($parts, 2))];
}
/**
* Process entry
*
* $entry = Entries::processEntry(PATH['entries'] . '/home/entry.html');
*
* @access public
* @param string $file_path File path
* @param bool $raw Raw or not raw content
* @param bool $ignore_content Ignore content parsing
* @return array|string
*/
public static function processEntry(string $file_path, bool $raw = false, bool $ignore_content = false)
{
// Get entry from file
$entry = trim(Filesystem::getFileContent($file_path));
// Return raw entry if $raw is true
if ($raw) {
return $entry;
} else {
// Create $entry_frontmatter and $entry_content
$entry = Entries::frontMatterParser($entry);
$entry_frontmatter = $entry['matter'];
$entry_content = $entry['body'];
// Create empty $_entry
$_entry = [];
// Process $entry_frontmatter with YAML and Shortcodes parsers
$_entry = YamlParser::decode(Entries::processShortcodes($entry_frontmatter));
// Create entry url item
$url = str_replace(PATH['entries'], Http::getBaseUrl(), $file_path);
$url = str_replace('entry.html', '', $url);
$url = str_replace('.html', '', $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 = rtrim($url, '/');
$_entry['url'] = $url;
// Create entry slug item
$url = str_replace(Http::getBaseUrl(), '', $url);
$url = ltrim($url, '/');
$url = rtrim($url, '/');
$_entry['slug'] = str_replace(Http::getBaseUrl(), '', $url);
// Create entry base url
$_entry['base_url'] = Http::getBaseUrl() . '/site/entries/';
// Create entry template item
$_entry['template'] = $_entry['template'] ?? 'default';
// Create entry date item
$_entry['date'] = $_entry['date'] ?? date(Registry::get('settings.date_format'), filemtime($file_path));
// Create entry content item with $entry_content
if ($ignore_content) {
$_entry['content'] = $entry_content;
} else {
$_entry['content'] = Entries::processContent($entry_content);
}
// Return entry
return $_entry;
}
}
/**
* Process shortcodes
*
* $content = Entries::processShortcodes($content);
*
* @access public
* @param string $content Content to parse
* @return string
*/
public static function processShortcodes(string $content) : string
{
return Entries::shortcode()->process($content);
}
/**
* Process content with markdown and shortcodes processors
*
* $content = Entries::processContent($content);
*
* @access public
* @param string $content Content to parse
* @return string
*/
public static function processContent(string $content) : string
{
return Entries::processShortcodes($content);
}
/**
* Init Parsers
*
* @access private
* @return void
*/
private static function initParsers() : void
{
// Init Shortcodes
Entries::initShortcodes();
}
/**
* Init Shortcodes
*
* @access private
* @return void
*/
private static function initShortcodes() : void
{
// Create Shortcode Parser object
Entries::$shortcode = new ShortcodeFacade();
// Event: Shortcodes initialized and now we can add our custom shortcodes
Event::dispatch('onShortcodesInitialized');
}
/**
* Display current entry
*
* @access private
* @return void
*/
private static function displayCurrentEntry() : void
{
Http::setRequestHeaders('Content-Type: text/html; charset='.Registry::get('settings.charset'));
Themes::view(empty(Entries::$entry['template']) ? 'templates/default' : 'templates/' . Entries::$entry['template'])
->assign('entry', Entries::$entry, true)
->display();
}
/**
* Get the Content instance.
*
* @access public
* @return object
*/
public static function getInstance()
{
if (is_null(Entries::$instance)) {
Entries::$instance = new self;
}
return Entries::$instance;
}
}

View File

@@ -1,185 +0,0 @@
<?php
/**
* @package Flextype
*
* @author Romanenko Sergey / Awilum <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 Flextype\Component\Http\Http;
use Flextype\Component\Session\Session;
use Flextype\Component\ErrorHandler\ErrorHandler;
use Flextype\Component\Registry\Registry;
use Flextype\Component\Filesystem\Filesystem;
class Flextype
{
/**
* The version of Flextype
*
* @var string
*/
const VERSION = '0.8.3';
/**
* An instance of the Flextype class
*
* @var object
* @access private
*/
private static $instance = null;
/**
* Private clone method to enforce singleton behavior.
*
* @access private
*/
private function __clone()
{
}
/**
* Private wakeup method to enforce singleton behavior.
*
* @access private
*/
private function __wakeup()
{
}
/**
* Private construct method to enforce singleton behavior.
*
* @access private
*/
private function __construct()
{
Flextype::init();
}
/**
* Init Flextype Application
*
* @access private
*/
private static function init() : void
{
// Turn on output buffering
ob_start();
// Set Flextype config
Flextype::setConfig();
// Set internal encoding
function_exists('mb_language') and mb_language('uni');
function_exists('mb_regex_encoding') and mb_regex_encoding(Registry::get('settings.charset'));
function_exists('mb_internal_encoding') and mb_internal_encoding(Registry::get('settings.charset'));
// Set error handler
Flextype::setErrorHandler();
// Set default timezone
date_default_timezone_set(Registry::get('settings.timezone'));
// Start the session
Session::start();
// Get Cache Instance
Cache::getInstance();
// Get Images Instance
Images::getInstance();
// Get Snippets Instance
Snippets::getInstance();
// Get Themes Instance
Themes::getInstance();
// Get Plugins Instance
Plugins::getInstance();
// Get Entries Instance
Entries::getInstance();
// Flush (send) the output buffer and turn off output buffering
ob_end_flush();
}
/**
* Set error handler
*
* @access private
*/
private static function setErrorHandler() : void
{
// Display Errors
if (Registry::get('settings.errors.display')) {
define('DEVELOPMENT', true);
error_reporting(-1);
} else {
define('DEVELOPMENT', false);
error_reporting(0);
}
// Create directory for logs
!Filesystem::fileExists(LOGS_PATH) and Filesystem::createDir(LOGS_PATH);
// Set Error handler
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 config
*
* @access private
*/
private static function setConfig() : void
{
// Set empty site settings array
Registry::set('settings', []);
// Set settings files path
$default_settings_file_path = PATH['config']['default'] . '/settings.yaml';
$site_settings_file_path = PATH['config']['site'] . '/settings.yaml';
// Set settings if Flextype settings and Site settings config files exist
if (Filesystem::fileExists($default_settings_file_path) && Filesystem::fileExists($site_settings_file_path)) {
// Get Flextype settings and Site settings
$default_settings = YamlParser::decode(Filesystem::getFileContent($default_settings_file_path));
$site_settings = YamlParser::decode(Filesystem::getFileContent($site_settings_file_path));
// Merge settings
$settings = array_replace_recursive($default_settings, $site_settings);
// Set settings
Registry::set('settings', $settings);
} else {
throw new \RuntimeException("Flextype settings and Site settings config files does not exist.");
}
}
/**
* Get the Flextype instance.
*
* @access public
* @return object
*/
public static function getInstance()
{
if (is_null(Flextype::$instance)) {
Flextype::$instance = new self;
}
return Flextype::$instance;
}
}

View File

@@ -1,274 +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 Flextype\Component\Http\Http;
use Flextype\Component\Event\Event;
use Flextype\Component\Html\Html;
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
// Event: onShortcodesInitialized
Event::addListener('onShortcodesInitialized', function () {
// Shortcode: [image path="home/image.jpg"]
// Result: Display image
Entries::shortcode()->addHandler('image', function(ShortcodeInterface $s) {
$params = [];
$attributes = [];
// API
// http://glide.thephpleague.com/1.0/api/quick-reference/
($s->getParameter('or')) and $params['or'] = $s->getParameter('or');
($s->getParameter('flip')) and $params['flip'] = $s->getParameter('flip');
($s->getParameter('crop')) and $params['crop'] = $s->getParameter('crop');
($s->getParameter('w')) and $params['w'] = $s->getParameter('w');
($s->getParameter('h')) and $params['h'] = $s->getParameter('h');
($s->getParameter('fit')) and $params['fit'] = $s->getParameter('fit');
($s->getParameter('dpr')) and $params['dpr'] = $s->getParameter('dpr');
($s->getParameter('bri')) and $params['bri'] = $s->getParameter('bri');
($s->getParameter('con')) and $params['con'] = $s->getParameter('con');
($s->getParameter('gam')) and $params['gam'] = $s->getParameter('gam');
($s->getParameter('sharp')) and $params['sharp'] = $s->getParameter('sharp');
($s->getParameter('blur')) and $params['blur'] = $s->getParameter('blur');
($s->getParameter('pixel')) and $params['pixel'] = $s->getParameter('pixel');
($s->getParameter('filt')) and $params['filt'] = $s->getParameter('filt');
($s->getParameter('mark')) and $params['mark'] = $s->getParameter('mark');
($s->getParameter('markw')) and $params['markw'] = $s->getParameter('markw');
($s->getParameter('markh')) and $params['markh'] = $s->getParameter('markh');
($s->getParameter('markx')) and $params['markx'] = $s->getParameter('markx');
($s->getParameter('marky')) and $params['marky'] = $s->getParameter('marky');
($s->getParameter('markpad')) and $params['markpad'] = $s->getParameter('markpad');
($s->getParameter('markpos')) and $params['markpos'] = $s->getParameter('markpos');
($s->getParameter('markalpha')) and $params['markalpha'] = $s->getParameter('markalpha');
($s->getParameter('bg')) and $params['bg'] = $s->getParameter('bg');
($s->getParameter('border')) and $params['border'] = $s->getParameter('border');
($s->getParameter('q')) and $params['q'] = $s->getParameter('q');
($s->getParameter('fm')) and $params['fm'] = $s->getParameter('fm');
($s->getParameter('width')) and $attributes['width'] = $s->getParameter('width');
($s->getParameter('height')) and $attributes['height'] = $s->getParameter('height');
($s->getParameter('class')) and $attributes['class'] = $s->getParameter('class');
($s->getParameter('id')) and $attributes['id'] = $s->getParameter('id');
($s->getParameter('alt')) and $attributes['alt'] = $s->getParameter('alt');
return Images::getImage($s->getParameter('path'), $params, $attributes);
});
// Shortcode: [image_url path="home/image.jpg"]
// Result: Display image url
Entries::shortcode()->addHandler('image_url', function(ShortcodeInterface $s) {
$params = [];
// API
// http://glide.thephpleague.com/1.0/api/quick-reference/
($s->getParameter('or')) and $params['or'] = $s->getParameter('or');
($s->getParameter('flip')) and $params['flip'] = $s->getParameter('flip');
($s->getParameter('crop')) and $params['crop'] = $s->getParameter('crop');
($s->getParameter('w')) and $params['w'] = $s->getParameter('w');
($s->getParameter('h')) and $params['h'] = $s->getParameter('h');
($s->getParameter('fit')) and $params['fit'] = $s->getParameter('fit');
($s->getParameter('dpr')) and $params['dpr'] = $s->getParameter('dpr');
($s->getParameter('bri')) and $params['bri'] = $s->getParameter('bri');
($s->getParameter('con')) and $params['con'] = $s->getParameter('con');
($s->getParameter('gam')) and $params['gam'] = $s->getParameter('gam');
($s->getParameter('sharp')) and $params['sharp'] = $s->getParameter('sharp');
($s->getParameter('blur')) and $params['blur'] = $s->getParameter('blur');
($s->getParameter('pixel')) and $params['pixel'] = $s->getParameter('pixel');
($s->getParameter('filt')) and $params['filt'] = $s->getParameter('filt');
($s->getParameter('mark')) and $params['mark'] = $s->getParameter('mark');
($s->getParameter('markw')) and $params['markw'] = $s->getParameter('markw');
($s->getParameter('markh')) and $params['markh'] = $s->getParameter('markh');
($s->getParameter('markx')) and $params['markx'] = $s->getParameter('markx');
($s->getParameter('marky')) and $params['marky'] = $s->getParameter('marky');
($s->getParameter('markpad')) and $params['markpad'] = $s->getParameter('markpad');
($s->getParameter('markpos')) and $params['markpos'] = $s->getParameter('markpos');
($s->getParameter('markalpha')) and $params['markalpha'] = $s->getParameter('markalpha');
($s->getParameter('bg')) and $params['bg'] = $s->getParameter('bg');
($s->getParameter('border')) and $params['border'] = $s->getParameter('border');
($s->getParameter('q')) and $params['q'] = $s->getParameter('q');
($s->getParameter('fm')) and $params['fm'] = $s->getParameter('fm');
return Images::getImageUrl($s->getParameter('path'), $params);
});
});
class Images
{
/**
* An instance of the Themes class
*
* @var object
*/
private static $instance = null;
/**
* Images Server
*
* @var
*/
protected static $server;
/**
* Private clone method to enforce singleton behavior.
*
* @access private
*/
private function __clone()
{
}
/**
* Private wakeup method to enforce singleton behavior.
*
* @access private
*/
private function __wakeup()
{
}
/**
* Private construct method to enforce singleton behavior.
*
* @access private
*/
private function __construct()
{
Images::init();
}
/**
* Init Images
*
* @access private
* @return void
*/
private static function init() : void
{
// Set source filesystem
$source = new \League\Flysystem\Filesystem(
new \League\Flysystem\Adapter\Local(PATH['entries'])
);
// Set cache filesystem
$cache = new \League\Flysystem\Filesystem(
new \League\Flysystem\Adapter\Local(PATH['cache'] . '/glide')
);
// Set watermarks filesystem
$watermarks = new \League\Flysystem\Filesystem(
new \League\Flysystem\Adapter\Local(PATH['site'] . '/watermarks')
);
// Set image manager
$imageManager = new \Intervention\Image\ImageManager([
'driver' => 'gd',
]);
// Set manipulators
$manipulators = [
new \League\Glide\Manipulators\Orientation(),
new \League\Glide\Manipulators\Crop(),
new \League\Glide\Manipulators\Size(2000*2000),
new \League\Glide\Manipulators\Brightness(),
new \League\Glide\Manipulators\Contrast(),
new \League\Glide\Manipulators\Gamma(),
new \League\Glide\Manipulators\Sharpen(),
new \League\Glide\Manipulators\Filter(),
new \League\Glide\Manipulators\Blur(),
new \League\Glide\Manipulators\Pixelate(),
new \League\Glide\Manipulators\Watermark($watermarks),
new \League\Glide\Manipulators\Background(),
new \League\Glide\Manipulators\Border(),
new \League\Glide\Manipulators\Encode(),
];
// Set API
$api = new \League\Glide\Api\Api($imageManager, $manipulators);
// Setup Glide server
$server = new \League\Glide\Server(
$source,
$cache,
$api
);
Images::$server = $server;
}
/**
* Get image url
*
* Images::getImageUrl('page-name/image.jpg', [w => '200']);
* http://glide.thephpleague.com/1.0/api/quick-reference/
*
* @access public
* @param string $path Image path
* @param array $params Image params
* @return string
*/
public static function getImageUrl($path, array $params)
{
if (file_exists(PATH['entries'] . '/' . $path)) {
return Http::getBaseUrl() . '/site/cache/glide/' . Images::$server->makeImage($path, $params);
} else {
return "File {$path} does not exist.";
}
}
/**
* Get image
*
* Images::getImage('page-name/image.jpg', [w => '200']);
* http://glide.thephpleague.com/1.0/api/quick-reference/
*
* @access public
* @param string $path Image path
* @param array $params Image params
* @param array $attributes Image html attributes
* @return string
*/
public static function getImage($path, array $params, array $attributes = [])
{
if (file_exists(PATH['entries'] . '/' . $path)) {
return '<img '.Html::attributes($attributes).' src="'. Images::getImageUrl($path, $params) .'">';
} else {
return "File {$path} does not exist.";
}
}
/**
* Returns server variable
*
* @access public
* @return object
*/
public static function server()
{
return Images::$server;
}
/**
* Get the Image instance.
*
* @access public
* @return object
*/
public static function getInstance()
{
if (is_null(Images::$instance)) {
Images::$instance = new self;
}
return Images::$instance;
}
}

View File

@@ -1,38 +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 Flextype\Component\Filesystem\Filesystem;
class Menus
{
/**
* Get menu
*
* Menu::get('menu-name');
*
* @access public
* @param string $menu_name Menu name
* @return array
*/
public static function get(string $menu_name)
{
$menu_path = PATH['menus'] . '/' . $menu_name . '.yaml';
if (Filesystem::fileExists($menu_path)) {
return YamlParser::decode(Filesystem::getFileContent($menu_path));
} else {
throw new \RuntimeException("Menu {$menu_name} does not exist.");
}
}
}

View File

@@ -1,357 +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 Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Event\Event;
use Flextype\Component\I18n\I18n;
use Flextype\Component\Registry\Registry;
class Plugins
{
/**
* An instance of the Cache class
*
* @var object
* @access private
*/
private static $instance = null;
/**
* Locales array
*
* @var array
*/
private static $locales = [
'om' => 'Afaan Oromoo',
'aa' => 'Afaraf',
'af' => 'Afrikaans',
'ak' => 'Akan',
'an' => 'aragonés',
'ig' => 'Asụsụ Igbo',
'gn' => 'Avañe\'ẽ',
'ae' => 'avesta',
'ay' => 'aymar aru',
'az' => 'azərbaycan dili',
'id' => 'Bahasa Indonesia',
'ms' => 'bahasa Melayu',
'bm' => 'bamanankan',
'jv' => 'basa Jawa',
'su' => 'Basa Sunda',
'bi' => 'Bislama',
'bs' => 'bosanski jezik',
'br' => 'brezhoneg',
'ca' => 'català',
'ch' => 'Chamoru',
'ny' => 'chiCheŵa',
'sn' => 'chiShona',
'co' => 'corsu',
'cy' => 'Cymraeg',
'da' => 'dansk',
'se' => 'Davvisámegiella',
'de' => 'Deutsch',
'nv' => 'Diné bizaad',
'et' => 'eesti',
'na' => 'Ekakairũ Naoero',
'en' => 'English',
'es' => 'español',
'eo' => 'Esperanto',
'eu' => 'euskara',
'ee' => 'Eʋegbe',
'to' => 'faka Tonga',
'mg' => 'fiteny malagasy',
'fr' => 'français',
'fy' => 'Frysk',
'ff' => 'Fulfulde',
'fo' => 'føroyskt',
'ga' => 'Gaeilge',
'gv' => 'Gaelg',
'sm' => 'gagana fa\'a Samoa',
'gl' => 'galego',
'sq' => 'gjuha shqipe',
'gd' => 'Gàidhlig',
'ki' => 'Gĩkũyũ',
'ha' => 'Hausa',
'ho' => 'Hiri Motu',
'hr' => 'hrvatski jezik',
'io' => 'Ido',
'rw' => 'Ikinyarwanda',
'rn' => 'Ikirundi',
'ia' => 'Interlingua',
'nd' => 'isiNdebele',
'nr' => 'isiNdebele',
'xh' => 'isiXhosa',
'zu' => 'isiZulu',
'it' => 'italiano',
'ik' => 'Iñupiaq',
'pl' => 'język polski',
'mh' => 'Kajin M̧ajeļ',
'kl' => 'kalaallisut',
'kr' => 'Kanuri',
'kw' => 'Kernewek',
'kg' => 'KiKongo',
'sw' => 'Kiswahili',
'ht' => 'Kreyòl ayisyen',
'kj' => 'Kuanyama',
'ku' => 'Kurdî',
'la' => 'latine',
'lv' => 'latviešu valoda',
'lt' => 'lietuvių kalba',
'ro' => 'limba română',
'li' => 'Limburgs',
'ln' => 'Lingála',
'lg' => 'Luganda',
'lb' => 'Lëtzebuergesch',
'hu' => 'magyar',
'mt' => 'Malti',
'nl' => 'Nederlands',
'no' => 'Norsk',
'nb' => 'Norsk bokmål',
'nn' => 'Norsk nynorsk',
'uz' => 'O\'zbek',
'oc' => 'occitan',
'ie' => 'Interlingue',
'hz' => 'Otjiherero',
'ng' => 'Owambo',
'pt' => 'português',
'ty' => 'Reo Tahiti',
'rm' => 'rumantsch grischun',
'qu' => 'Runa Simi',
'sc' => 'sardu',
'za' => 'Saɯ cueŋƅ',
'st' => 'Sesotho',
'tn' => 'Setswana',
'ss' => 'SiSwati',
'sl' => 'slovenski jezik',
'sk' => 'slovenčina',
'so' => 'Soomaaliga',
'fi' => 'suomi',
'sv' => 'Svenska',
'mi' => 'te reo Māori',
'vi' => 'Tiếng Việt',
'lu' => 'Tshiluba',
've' => 'Tshivenḓa',
'tw' => 'Twi',
'tk' => 'Türkmen',
'tr' => 'Türkçe',
'ug' => 'Uyƣurqə',
'vo' => 'Volapük',
'fj' => 'vosa Vakaviti',
'wa' => 'walon',
'tl' => 'Wikang Tagalog',
'wo' => 'Wollof',
'ts' => 'Xitsonga',
'yo' => 'Yorùbá',
'sg' => 'yângâ tî sängö',
'is' => 'Íslenska',
'cs' => 'čeština',
'el' => 'ελληνικά',
'av' => 'авар мацӀ',
'ab' => 'аҧсуа бызшәа',
'ba' => 'башҡорт теле',
'be' => 'беларуская мова',
'bg' => 'български език',
'os' => 'ирон æвзаг',
'kv' => 'коми кыв',
'ky' => 'Кыргызча',
'mk' => 'македонски јазик',
'mn' => 'монгол',
'ce' => 'нохчийн мотт',
'ru' => 'Русский язык',
'sr' => 'српски језик',
'tt' => 'татар теле',
'tg' => 'тоҷикӣ',
'uk' => 'Українська',
'cv' => 'чӑваш чӗлхи',
'cu' => 'ѩзыкъ словѣньскъ',
'kk' => 'қазақ тілі',
'hy' => 'Հայերեն',
'yi' => 'ייִדיש',
'he' => 'עברית',
'ur' => 'اردو',
'ar' => 'العربية',
'fa' => 'فارسی',
'ps' => 'پښتو',
'ks' => 'कश्मीरी',
'ne' => 'नेपाली',
'pi' => 'पाऴि',
'bh' => 'भोजपुरी',
'mr' => 'मराठी',
'sa' => 'संस्कृतम्',
'sd' => 'सिन्धी',
'hi' => 'हिन्दी',
'as' => 'অসমীয়া',
'bn' => 'বাংলা',
'pa' => 'ਪੰਜਾਬੀ',
'gu' => 'ગુજરાતી',
'or' => 'ଓଡ଼ିଆ',
'ta' => 'தமிழ்',
'te' => 'తెలుగు',
'kn' => 'ಕನ್ನಡ',
'ml' => 'മലയാളം',
'si' => 'සිංහල',
'th' => 'ไทย',
'lo' => 'ພາສາລາວ',
'bo' => 'བོད་ཡིག',
'dz' => 'རྫོང་ཁ',
'my' => 'ဗမာစာ',
'ka' => 'ქართული',
'ti' => 'ትግርኛ',
'am' => 'አማርኛ',
'iu' => 'ᐃᓄᒃᑎᑐᑦ',
'oj' => 'ᐊᓂᔑᓈᐯᒧᐎᓐ',
'cr' => 'ᓀᐦᐃᔭᐍᐏᐣ',
'km' => 'ខ្មែរ',
'zh' => '中文 (Zhōngwén)',
'ja' => '日本語 (にほんご)',
'ii' => 'ꆈꌠ꒿ Nuosuhxop',
'ko' => '한국어 (韓國語)'
];
/**
* Private clone method to enforce singleton behavior.
*
* @access private
*/
private function __clone()
{
}
/**
* Private wakeup method to enforce singleton behavior.
*
* @access private
*/
private function __wakeup()
{
}
/**
* Private construct method to enforce singleton behavior.
*
* @access private
*/
private function __construct()
{
Plugins::init();
}
/**
* Init Plugins
*
* @access private
* @return void
*/
private static function init() : void
{
// Plugin cache id
$plugins_cache_id = '';
$_plugins_cache_id = '';
// Set empty plugins item
Registry::set('plugins', []);
// Get Plugins List
$plugins_list = Filesystem::getDirList(PATH['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 (Filesystem::fileExists($_plugin_settings = PATH['plugins'] . '/' . $plugin . '/settings.yaml') and
Filesystem::fileExists($_plugin_config = PATH['plugins'] . '/' . $plugin . '/'. $plugin .'.yaml')) {
$_plugins_cache_id .= filemtime($_plugin_settings) . filemtime($_plugin_config);
}
}
// Create Unique Cache ID for Plugins
$plugins_cache_id = md5('plugins' . PATH['plugins'] . '/' . $_plugins_cache_id);
// Get plugins list from cache or scan plugins folder and create new plugins cache item
if (Cache::contains($plugins_cache_id)) {
Registry::set('plugins', Cache::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 (Filesystem::fileExists($_plugin_settings = PATH['plugins'] . '/' . $plugin . '/settings.yaml')) {
$plugin_settings = YamlParser::decode(Filesystem::getFileContent($_plugin_settings));
}
if (Filesystem::fileExists($_plugin_config = PATH['plugins'] . '/' . $plugin . '/'. $plugin. '.yaml')) {
$plugin_config = YamlParser::decode(Filesystem::getFileContent($_plugin_config));
}
$_plugins_config[basename($_plugin_config, '.yaml')] = array_merge($plugin_settings, $plugin_config);
}
Registry::set('plugins', $_plugins_config);
Cache::save($plugins_cache_id, $_plugins_config);
}
}
// Create Dictionary
if (is_array($plugins_list) && count($plugins_list) > 0) {
foreach (Plugins::$locales as $locale => $locale_title) {
foreach ($plugins_list as $plugin) {
$language_file = PATH['plugins'] . '/' . $plugin . '/languages/' . $locale . '.yaml';
if (Filesystem::fileExists($language_file)) {
I18n::add(YamlParser::decode(Filesystem::getFileContent($language_file)), $locale);
}
}
}
}
// Include enabled plugins
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 PATH['plugins'] . '/' . $plugin_name .'/'. $plugin_name . '.php';
}
}
}
Event::dispatch('onPluginsInitialized');
}
}
/**
* Get locales.
*
* @access public
* @return array
*/
public static function getLocales() : array
{
return Plugins::$locales;
}
/**
* Get the Plugins instance.
*
* @access public
* @return object
*/
public static function getInstance()
{
if (is_null(Plugins::$instance)) {
Plugins::$instance = new self;
}
return Plugins::$instance;
}
}

View File

@@ -1,126 +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 Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Event\Event;
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
// Event: onShortcodesInitialized
Event::addListener('onShortcodesInitialized', function () {
// Shortcode: [snippet name=snippet-name]
Entries::shortcode()->addHandler('snippet', function(ShortcodeInterface $s) {
return Snippets::get($s->getParameter('name'));
});
});
class Snippets
{
/**
* An instance of the Snippets class
*
* @var object
*/
private static $instance = null;
/**
* Images Server
*
* @var
*/
protected static $server;
/**
* Private clone method to enforce singleton behavior.
*
* @access private
*/
private function __clone()
{
}
/**
* Private wakeup method to enforce singleton behavior.
*
* @access private
*/
private function __wakeup()
{
}
/**
* Private construct method to enforce singleton behavior.
*
* @access private
*/
private function __construct()
{
Snippets::init();
}
/**
* Init Snippets
*
* @access private
* @return void
*/
private static function init() : void
{
}
/**
* Get snippet
*
* Snippets::get('snippet-name');
*
* @access public
* @param string $snippet_name Snippet name
* @return string|bool Returns the contents of the output buffer and end output buffering.
* If output buffering isn't active then FALSE is returned.
*/
public static function get(string $snippet_name)
{
$snippet_path = PATH['snippets'] . '/' . $snippet_name . '.php';
if (Filesystem::fileExists($snippet_path)) {
// Turn on output buffering
ob_start();
// Include view file
include $snippet_path;
// Output...
return ob_get_clean();
} else {
throw new \RuntimeException("Snippet {$snippet_name} does not exist.");
}
}
/**
* Get the Snippets instance.
*
* @access public
* @return object
*/
public static function getInstance()
{
if (is_null(Snippets::$instance)) {
Snippets::$instance = new self;
}
return Snippets::$instance;
}
}

View File

@@ -1,231 +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 Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\View\View;
use Flextype\Component\Registry\Registry;
class Themes
{
/**
* An instance of the Themes class
*
* @var object
*/
private static $instance = null;
/**
* Private clone method to enforce singleton behavior.
*
* @access private
*/
private function __clone()
{
}
/**
* Private wakeup method to enforce singleton behavior.
*
* @access private
*/
private function __wakeup()
{
}
/**
* Private construct method to enforce singleton behavior.
*
* @access private
*/
private function __construct()
{
Themes::init();
}
/**
* Init Themes
*
* @access private
* @return void
*/
private static function init() : void
{
// Theme Manifest
$theme_manifest = [];
// Theme cache id
$theme_cache_id = '';
// Get current theme
$theme = Registry::get('settings.theme');
// Set empty themes items
Registry::set('themes', []);
// Create Unique Cache ID for Theme
$theme_cache_id = md5('theme' . filemtime(PATH['themes'] .'/'. $theme . '/' . 'settings.yaml') .
filemtime(PATH['themes'] .'/'. $theme . '/' . $theme . '.yaml'));
// Get Theme mafifest file and write to settings.themes array
if (Cache::contains($theme_cache_id)) {
Registry::set('themes.'.Registry::get('settings.theme'), Cache::fetch($theme_cache_id));
} else {
if (Filesystem::fileExists($theme_settings = PATH['themes'] . '/' . $theme . '/' . 'settings.yaml') and
Filesystem::fileExists($theme_config = PATH['themes'] . '/' . $theme . '/' . $theme . '.yaml')) {
$theme_settings = YamlParser::decode(Filesystem::getFileContent($theme_settings));
$theme_config = YamlParser::decode(Filesystem::getFileContent($theme_config));
$_theme = array_merge($theme_settings, $theme_config);
Registry::set('themes.'.Registry::get('settings.theme'), $_theme);
Cache::save($theme_cache_id, $_theme);
}
}
}
/**
* Get themes view
*
* @param string $template Template file
* @param string $variables Variables
* @access public
* @return object
*/
public static function view(string $template, array $variables = [])
{
// Set view file
// From current theme folder or from plugin folder
if (Filesystem::fileExists(PATH['themes'] . '/' . Registry::get('settings.theme') . '/views/' . $template . View::$view_ext)) {
$template = PATH['themes'] . '/' . Registry::get('settings.theme') . '/views/' . $template;
} else {
$template = PATH['plugins'] . '/' . $template;
}
// Return template
return new View($template, $variables);
}
/**
* Get partials for current theme
*
* @access public
* @return array
*/
public static function getPartials() : array
{
$partials = [];
// Get templates files
$_partials = Filesystem::getFilesList(PATH['themes'] . '/' . Registry::get('settings.theme') . '/views/partials/', 'php');
// If there is any template file then go...
if (count($_partials) > 0) {
foreach ($_partials as $partial) {
if (!is_bool(Themes::_strrevpos($partial, '/partials/'))) {
$partial_name = str_replace('.php', '', substr($partial, Themes::_strrevpos($partial, '/partials/')+strlen('/partials/')));
$partials[$partial_name] = $partial_name;
}
}
}
// return partials
return $partials;
}
/**
* Get templates for current theme
*
* @access public
* @return array
*/
public static function getTemplates() : array
{
$templates = [];
// Get templates files
$_templates = Filesystem::getFilesList(PATH['themes'] . '/' . Registry::get('settings.theme') . '/views/templates/', 'php');
// If there is any template file then go...
if (count($_templates) > 0) {
foreach ($_templates as $template) {
if (!is_bool(Themes::_strrevpos($template, '/templates/'))) {
$template_name = str_replace('.php', '', substr($template, Themes::_strrevpos($template, '/templates/')+strlen('/templates/')));
$templates[$template_name] = $template_name;
}
}
}
// return templates
return $templates;
}
/**
* Get Fieldsets for current theme
*
* @access public
* @return array
*/
public static function getFieldsets() : array
{
$fieldsets = [];
// Get fieldsets files
$_fieldsets = Filesystem::getFilesList(PATH['themes'] . '/' . Registry::get('settings.theme') . '/fieldsets/', 'yaml');
// If there is any template file then go...
if (count($_fieldsets) > 0) {
foreach ($_fieldsets as $fieldset) {
if (!is_bool(Themes::_strrevpos($fieldset, '/fieldsets/'))) {
$fieldset_name = str_replace('.yaml', '', substr($fieldset, Themes::_strrevpos($fieldset, '/fieldsets/')+strlen('/fieldsets/')));
$fieldset = YamlParser::decode(Filesystem::getFileContent($fieldset));
$fieldsets[$fieldset_name] = $fieldset['title'];
}
}
}
// return fieldsets
return $fieldsets;
}
/**
* _strrevpos
*
* @param string $instr instr
* @param string $needle needle
*
* @return bool
*/
private static function _strrevpos($instr, $needle)
{
$rev_pos = strpos(strrev($instr), strrev($needle));
if ($rev_pos === false) {
return false;
} else {
return strlen($instr) - $rev_pos - strlen($needle);
}
}
/**
* Get the Themes instance.
*
* @access public
* @return object
*/
public static function getInstance()
{
if (is_null(Themes::$instance)) {
Themes::$instance = new self;
}
return Themes::$instance;
}
}

149
flextype/bootstrap.php Executable file
View File

@@ -0,0 +1,149 @@
<?php
/**
* @package Flextype
*
* @author Romanenko Sergey <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
use Flextype\Component\Session\Session;
use Flextype\Component\Registry\Registry;
use Flextype\Component\Filesystem\Filesystem;
/**
* The version of Flextype
*
* @var string
*/
define('FLEXTYPE_VERSION', '0.9.0');
// Start the session
Session::start();
// Configure application
$config = [
'settings' => [
'debug' => false,
'whoops.editor' => 'atom',
'whoops.page_title' => 'Error!',
'displayErrorDetails' => false,
'addContentLengthHeader' => true,
'addContentLengthHeader' => false,
'routerCacheFile' => false,
'determineRouteBeforeAppMiddleware' => false,
'outputBuffering' => 'append',
'responseChunkSize' => 4096,
'httpVersion' => '1.1',
'twig' => [
'cache' => PATH['cache'] . '/twig',
'auto_reload' => true
],
'images' => [
'driver' => 'gd',
],
],
];
/**
* Create new application
*/
$app = new \Slim\App($config);
/**
* Set Flextype Dependency Injection Container
*/
$flextype = $app->getContainer();
/**
* Include Dependencies
*/
include_once 'dependencies.php';
/**
* Include Middlewares
*/
include_once 'middlewares.php';
/**
* Include Routes (web)
*/
include_once 'routes/web.php';
// Set empty settings array
$flextype['registry']->set('settings', []);
// Set settings files path
$default_settings_file_path = PATH['config']['default'] . '/settings.json';
$site_settings_file_path = PATH['config']['site'] . '/settings.json';
// Set settings if Flextype settings and Site settings config files exist
if (Filesystem::has($default_settings_file_path) && Filesystem::has($site_settings_file_path)) {
if (($content = Filesystem::read($default_settings_file_path)) === false) {
throw new \RuntimeException('Load file: ' . $default_settings_file_path . ' - failed!');
} else {
$default_settings = JsonParser::decode($content);
}
if (($content = Filesystem::read($site_settings_file_path)) === false) {
throw new \RuntimeException('Load file: ' . $site_settings_file_path . ' - failed!');
} else {
$site_settings = JsonParser::decode($content);
}
// Merge settings
$settings = array_replace_recursive($default_settings, $site_settings);
// Set settings
$flextype['registry']->set('settings', $settings);
} else {
throw new \RuntimeException("Flextype settings and Site settings config files does not exist.");
}
// Set internal encoding
function_exists('mb_language') and mb_language('uni');
function_exists('mb_regex_encoding') and mb_regex_encoding($flextype['registry']->get('settings.charset'));
function_exists('mb_internal_encoding') and mb_internal_encoding($flextype['registry']->get('settings.charset'));
// Display Errors
if ($flextype['registry']->get('settings.errors.display')) {
/**
* Add WhoopsMiddleware
*/
$app->add(new \Zeuxisoo\Whoops\Provider\Slim\WhoopsMiddleware($app));
} else {
error_reporting(0);
}
// Set default timezone
date_default_timezone_set($flextype['registry']->get('settings.timezone'));
// Get Default Shortocdes List
$shortcodes_list = Filesystem::listContents(ROOT_DIR . '/flextype/shortcodes');
// Include default shortcodes
foreach ($shortcodes_list as $shortcode) {
include_once $shortcode['path'];
}
/**
* Init themes
*/
$flextype['themes']->init($flextype, $app);
/**
* Init plugins
*/
$flextype['plugins']->init($flextype, $app);
/**
* Run application
*/
$app->run();

View File

@@ -0,0 +1,636 @@
{
"af": {
"name": "Afrikaans",
"nativeName": "Afrikaans"
},
"af_ZA": {
"name": "Afrikaans",
"nativeName": "Afrikaans"
},
"ak": {
"name": "Akan",
"nativeName": "Akan"
},
"ast": {
"name": "Asturian",
"nativeName": "Asturianu"
},
"ar": {
"name": "Arabic",
"nativeName": "عربي",
"orientation": "rtl"
},
"ar_SA": {
"name": "Arabic",
"nativeName": "عربي",
"orientation": "rtl"
},
"as": {
"name": "Assamese",
"nativeName": "অসমীয়া"
},
"be": {
"name": "Belarusian",
"nativeName": "Беларуская"
},
"bg": {
"name": "Bulgarian",
"nativeName": "Български"
},
"bn": {
"name": "Bengali",
"nativeName": "বাংলা"
},
"bn_BD": {
"name": "Bengali (Bangladesh)",
"nativeName": "বাংলা (বাংলাদেশ)"
},
"bn_IN": {
"name": "Bengali (India)",
"nativeName": "বাংলা (ভারত)"
},
"br": {
"name": "Breton",
"nativeName": "Brezhoneg"
},
"bs": {
"name": "Bosnian",
"nativeName": "Bosanski"
},
"ca": {
"name": "Catalan",
"nativeName": "Català"
},
"ca_ES": {
"name": "Catalan",
"nativeName": "Català"
},
"ca_valencia": {
"name": "Catalan (Valencian)",
"nativeName": "Català (valencià)"
},
"cs": {
"name": "Czech",
"nativeName": "Čeština"
},
"cs_CZ": {
"name": "Czech",
"nativeName": "Čeština"
},
"cy": {
"name": "Welsh",
"nativeName": "Cymraeg"
},
"da": {
"name": "Danish",
"nativeName": "Dansk"
},
"da_DK": {
"name": "Danish",
"nativeName": "Dansk"
},
"de": {
"name": "German",
"nativeName": "Deutsch"
},
"de_AT": {
"name": "German (Austria)",
"nativeName": "Deutsch (Österreich)"
},
"de_CH": {
"name": "German (Switzerland)",
"nativeName": "Deutsch (Schweiz)"
},
"de_DE": {
"name": "German (Germany)",
"nativeName": "Deutsch (Deutschland)"
},
"dsb": {
"name": "Lower Sorbian",
"nativeName": "Dolnoserbšćina"
},
"el": {
"name": "Greek",
"nativeName": "Ελληνικά"
},
"el_GR": {
"name": "Greek",
"nativeName": "Ελληνικά"
},
"en": {
"name": "English",
"nativeName": "English"
},
"en_AU": {
"name": "English (Australian)",
"nativeName": "English (Australian)"
},
"en_CA": {
"name": "English (Canadian)",
"nativeName": "English (Canadian)"
},
"en_GB": {
"name": "English (British)",
"nativeName": "English (British)"
},
"en_NZ": {
"name": "English (New Zealand)",
"nativeName": "English (New Zealand)"
},
"en_US": {
"name": "English (US)",
"nativeName": "English (US)"
},
"en_ZA": {
"name": "English (South African)",
"nativeName": "English (South African)"
},
"eo": {
"name": "Esperanto",
"nativeName": "Esperanto"
},
"es": {
"name": "Spanish",
"nativeName": "Español"
},
"es_AR": {
"name": "Spanish (Argentina)",
"nativeName": "Español (de Argentina)"
},
"es_CL": {
"name": "Spanish (Chile)",
"nativeName": "Español (de Chile)"
},
"es_ES": {
"name": "Spanish (Spain)",
"nativeName": "Español (de España)"
},
"es_MX": {
"name": "Spanish (Mexico)",
"nativeName": "Español (de México)"
},
"et": {
"name": "Estonian",
"nativeName": "Eesti keel"
},
"eu": {
"name": "Basque",
"nativeName": "Euskara"
},
"fa": {
"name": "Persian",
"nativeName": "فارسی",
"orientation": "rtl"
},
"fi": {
"name": "Finnish",
"nativeName": "Suomi"
},
"fi_FI": {
"name": "Finnish",
"nativeName": "Suomi"
},
"fj_FJ": {
"name": "Fijian",
"nativeName": "Vosa vaka_Viti"
},
"fr": {
"name": "French",
"nativeName": "Français"
},
"fr_CA": {
"name": "French (Canada)",
"nativeName": "Français (Canada)"
},
"fr_FR": {
"name": "French (France)",
"nativeName": "Français (France)"
},
"fur": {
"name": "Friulian",
"nativeName": "Furlan"
},
"fur_IT": {
"name": "Friulian",
"nativeName": "Furlan"
},
"fy": {
"name": "Frisian",
"nativeName": "Frysk"
},
"fy_NL": {
"name": "Frisian",
"nativeName": "Frysk"
},
"ga": {
"name": "Irish",
"nativeName": "Gaeilge"
},
"ga_IE": {
"name": "Irish (Ireland)",
"nativeName": "Gaeilge (Éire)"
},
"gd": {
"name": "Gaelic (Scotland)",
"nativeName": "Gàidhlig"
},
"gl": {
"name": "Galician",
"nativeName": "Galego"
},
"gu": {
"name": "Gujarati",
"nativeName": "ગુજરાતી"
},
"gu_IN": {
"name": "Gujarati",
"nativeName": "ગુજરાતી"
},
"he": {
"name": "Hebrew",
"nativeName": "עברית",
"orientation": "rtl"
},
"he_IL": {
"name": "Hebrew",
"nativeName": "עברית",
"orientation": "rtl"
},
"hi": {
"name": "Hindi",
"nativeName": "हिन्दी"
},
"hi_IN": {
"name": "Hindi (India)",
"nativeName": "हिन्दी (भारत)"
},
"hr": {
"name": "Croatian",
"nativeName": "Hrvatski"
},
"hr_HR": {
"name": "Croatian",
"nativeName": "Hrvatski"
},
"hsb": {
"name": "Upper Sorbian",
"nativeName": "Hornjoserbsce"
},
"hu": {
"name": "Hungarian",
"nativeName": "Magyar"
},
"hu_HU": {
"name": "Hungarian",
"nativeName": "Magyar"
},
"hy": {
"name": "Armenian",
"nativeName": "Հայերեն"
},
"hy_AM": {
"name": "Armenian",
"nativeName": "Հայերեն"
},
"id": {
"name": "Indonesian",
"nativeName": "Bahasa Indonesia"
},
"is": {
"name": "Icelandic",
"nativeName": "íslenska"
},
"it": {
"name": "Italian",
"nativeName": "Italiano"
},
"it_IT": {
"name": "Italian",
"nativeName": "Italiano"
},
"ja": {
"name": "Japanese",
"nativeName": "日本語"
},
"ja_JP": {
"name": "Japanese",
"nativeName": "日本語"
},
"ka": {
"name": "Georgian",
"nativeName": "ქართული"
},
"kk": {
"name": "Kazakh",
"nativeName": "Қазақ"
},
"kn": {
"name": "Kannada",
"nativeName": "ಕನ್ನಡ"
},
"ko": {
"name": "Korean",
"nativeName": "한국어"
},
"ko_KR": {
"name": "Korean",
"nativeName": "한국어"
},
"ku": {
"name": "Kurdish",
"nativeName": "Kurdî"
},
"la": {
"name": "Latin",
"nativeName": "Latina"
},
"lb": {
"name": "Luxembourgish",
"nativeName": "Lëtzebuergesch"
},
"lg": {
"name": "Luganda",
"nativeName": "Luganda"
},
"lt": {
"name": "Lithuanian",
"nativeName": "Lietuvių kalba"
},
"lv": {
"name": "Latvian",
"nativeName": "Latviešu"
},
"mai": {
"name": "Maithili",
"nativeName": "मैथिली মৈথিলী"
},
"mg": {
"name": "Malagasy",
"nativeName": "Malagasy"
},
"mi": {
"name": "Maori (Aotearoa)",
"nativeName": "Māori (Aotearoa)"
},
"mk": {
"name": "Macedonian",
"nativeName": "Македонски"
},
"ml": {
"name": "Malayalam",
"nativeName": "മലയാളം"
},
"mn": {
"name": "Mongolian",
"nativeName": "Монгол"
},
"mr": {
"name": "Marathi",
"nativeName": "मराठी"
},
"no": {
"name": "Norwegian",
"nativeName": "Norsk"
},
"no_NO": {
"name": "Norwegian",
"nativeName": "Norsk"
},
"nb": {
"name": "Norwegian",
"nativeName": "Norsk"
},
"nb_NO": {
"name": "Norwegian (Bokmål)",
"nativeName": "Norsk bokmål"
},
"ne_NP": {
"name": "Nepali",
"nativeName": "नेपाली"
},
"nn_NO": {
"name": "Norwegian (Nynorsk)",
"nativeName": "Norsk nynorsk"
},
"nl": {
"name": "Dutch",
"nativeName": "Nederlands"
},
"nl_NL": {
"name": "Dutch",
"nativeName": "Nederlands"
},
"nr": {
"name": "Ndebele, South",
"nativeName": "IsiNdebele"
},
"nso": {
"name": "Northern Sotho",
"nativeName": "Sepedi"
},
"oc": {
"name": "Occitan (Lengadocian)",
"nativeName": "Occitan (lengadocian)"
},
"or": {
"name": "Oriya",
"nativeName": "ଓଡ଼ିଆ"
},
"pa": {
"name": "Punjabi",
"nativeName": "ਪੰਜਾਬੀ"
},
"pa_IN": {
"name": "Punjabi",
"nativeName": "ਪੰਜਾਬੀ"
},
"pl": {
"name": "Polish",
"nativeName": "Polski"
},
"pl_PL": {
"name": "Polish",
"nativeName": "Polski"
},
"pt": {
"name": "Portuguese",
"nativeName": "Português"
},
"pt_BR": {
"name": "Portuguese (Brazilian)",
"nativeName": "Português (do Brasil)"
},
"pt_PT": {
"name": "Portuguese (Portugal)",
"nativeName": "Português (Europeu)"
},
"ro": {
"name": "Romanian",
"nativeName": "Română"
},
"ro_RO": {
"name": "Romanian",
"nativeName": "Română"
},
"rm": {
"name": "Romansh",
"nativeName": "Rumantsch"
},
"ru": {
"name": "Russian",
"nativeName": "Русский"
},
"ru_RU": {
"name": "Russian",
"nativeName": "Русский"
},
"rw": {
"name": "Kinyarwanda",
"nativeName": "Ikinyarwanda"
},
"si": {
"name": "Sinhala",
"nativeName": "සිංහල"
},
"sk": {
"name": "Slovak",
"nativeName": "Slovenčina"
},
"sl": {
"name": "Slovenian",
"nativeName": "Slovensko"
},
"son": {
"name": "Songhai",
"nativeName": "Soŋay"
},
"sq": {
"name": "Albanian",
"nativeName": "Shqip"
},
"sr": {
"name": "Serbian",
"nativeName": "Српски"
},
"sr_SP": {
"name": "Serbian",
"nativeName": "Српски"
},
"sr_Latn": {
"name": "Serbian",
"nativeName": "Srpski"
},
"ss": {
"name": "Siswati",
"nativeName": "siSwati"
},
"st": {
"name": "Southern Sotho",
"nativeName": "Sesotho"
},
"sv": {
"name": "Swedish",
"nativeName": "Svenska"
},
"sv_SE": {
"name": "Swedish",
"nativeName": "Svenska"
},
"ta": {
"name": "Tamil",
"nativeName": "தமிழ்"
},
"ta_IN": {
"name": "Tamil (India)",
"nativeName": "தமிழ் (இந்தியா)"
},
"ta_LK": {
"name": "Tamil (Sri Lanka)",
"nativeName": "தமிழ் (இலங்கை)"
},
"te": {
"name": "Telugu",
"nativeName": "తెలుగు"
},
"th": {
"name": "Thai",
"nativeName": "ไทย"
},
"tlh": {
"name": "Klingon",
"nativeName": "Klingon"
},
"tn": {
"name": "Tswana",
"nativeName": "Setswana"
},
"tr": {
"name": "Turkish",
"nativeName": "Türkçe"
},
"tr_TR": {
"name": "Turkish",
"nativeName": "Türkçe"
},
"ts": {
"name": "Tsonga",
"nativeName": "Xitsonga"
},
"tt": {
"name": "Tatar",
"nativeName": "Tatarça"
},
"tt_RU": {
"name": "Tatar",
"nativeName": "Tatarça"
},
"uk": {
"name": "Ukrainian",
"nativeName": "Українська"
},
"uk_UA": {
"name": "Ukrainian",
"nativeName": "Українська"
},
"ur": {
"name": "Urdu",
"nativeName": "اُردو",
"orientation": "rtl"
},
"ve": {
"name": "Venda",
"nativeName": "Tshivenḓa"
},
"vi": {
"name": "Vietnamese",
"nativeName": "Tiếng Việt"
},
"vi_VN": {
"name": "Vietnamese",
"nativeName": "Tiếng Việt"
},
"wo": {
"name": "Wolof",
"nativeName": "Wolof"
},
"xh": {
"name": "Xhosa",
"nativeName": "isiXhosa"
},
"zh": {
"name": "Chinese (Simplified)",
"nativeName": "中文 (简体)"
},
"zh_CN": {
"name": "Chinese (Simplified)",
"nativeName": "中文 (简体)"
},
"zh_TW": {
"name": "Chinese (Traditional)",
"nativeName": "正體中文 (繁體)"
},
"zu": {
"name": "Zulu",
"nativeName": "isiZulu"
}
}

View File

@@ -0,0 +1,60 @@
{
"title":"Flextype",
"description":"Build fast, flexible, easier to manage websites with Flextype.",
"keywords":"flextype, php, cms, flat-file cms, flat cms, flatfile cms, html",
"robots":"index, follow",
"author":{
"email":"",
"name":""
},
"timezone":"UTC",
"charset":"UTF-8",
"date_format":"F d Y H:i:s",
"theme":"default",
"locale":"en_US",
"entries":{
"main":"home",
"media":{
"upload_images_quality":70,
"upload_images_width":1600,
"upload_images_height":0,
"accept_file_types":"gif, jpg, jpeg, png, ico, zip, tgz, txt, md, doc, docx, pdf, epub, xls, xlsx, ppt, pptx, mp3, ogg, wav, m4a, mp4, m4v, ogv, wmv, avi, webm, svg"
},
"error404":{
"title":"Error 404",
"description":"We're sorry but the page you are looking for doesn't appear to exist!",
"content":"We're sorry but the page you are looking for doesn't appear to exist!",
"template":"default"
}
},
"errors":{
"display":false
},
"cache":{
"enabled":true,
"prefix":"flextype",
"driver":"auto",
"lifetime":604800,
"memcache":{
"server":"localhost",
"port":11211
},
"memcached":{
"server":"localhost",
"port":11211
},
"redis":{
"socket":false,
"password":false,
"server":"localhost",
"port":6379
},
"sqlite3":{
"database":"flextype",
"table":"flextype"
}
},
"admin_panel":{
"theme":"light"
}
}

View File

@@ -1,121 +0,0 @@
# The title of the website
title: "Flextype"
# The description of the website
description: "Modern Open Source Flat-File Content Management System"
# The keywords of the website
keywords: "flextype, php, cms, flat-file cms, flat cms, flatfile cms, html"
# The robots of the website
robots: "index, follow"
# The name and email address of the website author
author:
email: ""
name: ""
# Set the timezone to be used on the website.
# For a list of valid timezone settings, see:
# http://php.net/manual/en/timezones.php
timezone: UTC
# Charset
#
# Set internal character encoding.
#
# Currently the following names are supported:
# http://php.net/manual/ru/function.mb-regex-encoding.php#121645
charset: UTF-8
# Valid date format
# see: http://php.net/manual/ru/function.date.php
date_format: "F d Y H:i:s"
# The theme to use.
#
# Don't edit the provided theme templates directly, because they get updated
# in next releases. If you wish to modify a default theme, copy its folder, and
# change the name here accordingly.
theme: default
# The locale that'll be used by the Flextype.
locale: "en"
# The entries settings
# Define the file types (extensions to be exact) that are acceptable for upload.
entries:
main: home
media:
upload_images_quality: 70
upload_images_width: 1600
upload_images_height: 0
accept_file_types: "gif, jpg, jpeg, png, ico, zip, tgz, txt, md, doc, docx, pdf, epub, xls, xlsx, ppt, pptx, mp3, ogg, wav, m4a, mp4, m4v, ogv, wmv, avi, webm, svg"
error404:
title: "Error 404"
description: "We're sorry but the page you are looking for doesn't appear to exist!"
content: "We're sorry but the page you are looking for doesn't appear to exist!"
template: "default"
# Display errors
#
# - display: Display errors or not.
errors:
display: false
# Cache
#
# - enabled: Set to true to enable caching
#
# - prefix: Cache prefix string (prevents cache conflicts)
#
# - driver: Available drivers: auto (will get one from installed cache drivers), apcu,
# apc, array, wincache, xcache, memcache, memcached, redis, file.
#
# - lifetime: Lifetime of cached data in seconds
#
# - redis.socket: Path to redis unix socket (e.g. /var/run/redis/redis.sock),
# false = use server and port to connect
#
# - redis.password Redis password
#
# - redis.server Redis server
#
# - redis.port Redis port
#
# - memcache.server Memcache server
#
# - memcache.port Memcache port
#
# - memcached.server Memcached server
#
# - memcached.port Memcached port
#
# - sqlite3.database SQLite3 Database
#
# - sqlite3.table SQLite3 Table
cache:
enabled: true
prefix: flextype
driver: auto
lifetime: 604800
memcache:
server: 'localhost'
port: 11211
memcached:
server: 'localhost'
port: 11211
redis:
socket: false
password: false
server: 'localhost'
port: 6379
sqlite3:
database: flextype
table: flextype
# Admin Panel
#
# - themes: Theme (dark, light)
admin_panel:
theme: light

407
flextype/core/Cache.php Executable file
View File

@@ -0,0 +1,407 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
use Flextype\Component\Filesystem\Filesystem;
use \Doctrine\Common\Cache as DoctrineCache;
class Cache
{
/**
* Flextype Dependency Container
*/
private $flextype;
/**
* Unique cache key
*
* @var string Cache key.
*/
private $key;
/**
* Lifetime
*
* @var int Lifetime.
*/
private $lifetime;
/**
* Current time
*
* @var int Current time.
*/
private $now;
/**
* Cache Driver
*
* @var DoctrineCache
*/
private $driver;
/**
* Constructor
*
* @access public
*/
public function __construct($flextype)
{
$this->flextype = $flextype;
// Create Cache Directory
!Filesystem::has(PATH['cache']) and Filesystem::createDir(PATH['cache']);
// Set current time
$this->now = time();
// Create cache key to allow invalidate all cache on configuration changes.
$this->key = ($this->flextype['registry']->get('settings.cache.prefix') ?? 'flextype') . '-' . md5(PATH['site'] . 'Flextype::VERSION');
// Get Cache Driver
$this->driver = $this->getCacheDriver();
// Set the cache namespace to our unique key
$this->driver->setNamespace($this->key);
}
/**
* Get Cache Driver
*
* @access public
* @return object
*/
public function getCacheDriver()
{
// Try to set default cache driver name
$driver_name = $this->setDefaultCacheDriverName($this->flextype['registry']->get('settings.cache.driver'));
// Set cache driver
return $this->setCacheDriver($driver_name);
}
protected function setCacheDriver(string $driver_name)
{
switch ($driver_name) {
case 'apcu':
$driver = $this->setApcuCacheDriver();
break;
case 'array':
$driver = $this->setArrayCacheDriver();
break;
case 'wincache':
$driver = $this->setWinCacheDriver();
break;
case 'memcached':
$driver = $this->setMemcachedCacheDriver();
break;
case 'sqlite3':
$driver = $this->setSQLite3CacheDriver();
break;
case 'zend':
$driver = $this->setZendDataCacheDriver();
break;
case 'redis':
$driver = $this->setRedisCacheDriver();
break;
default:
$driver = $this->setFilesystemCacheDriver();
break;
}
return $driver;
}
/**
* The ZendDataCache driver uses the Zend Data Cache API available in the Zend Platform.
*
* @access protected
*/
protected function setZendDataCacheDriver()
{
$driver = new DoctrineCache\ZendDataCache();
return $driver;
}
/**
* The SQLite3Cache driver stores the cache data in a SQLite database and depends on the sqlite3 extension
* http://php.net/manual/en/book.sqlite3.php
*
* @access protected
*/
protected function setSQLite3CacheDriver()
{
// Cache directory
$cache_directory = PATH['cache'] . '/doctrine/';
// Create doctrine cache directory if its not exists
!Filesystem::has($cache_directory) and Filesystem::createDir($cache_directory);
$db = new \SQLite3($cache_directory . $this->flextype['registry']->get('settings.cache.sqlite3.database', 'flextype') . '.db');
$driver = new DoctrineCache\SQLite3Cache($db, $this->flextype['registry']->get('settings.cache.sqlite3.table', 'flextype'));
return $driver;
}
/**
* The MemcachedCache drivers stores the cache data in Memcached.
*
* @access protected
*/
protected function setMemcachedCacheDriver()
{
$memcached = new \Memcached();
$memcached->addServer(
$this->flextype['registry']->get('settings.cache.memcached.server', 'localhost'),
$this->flextype['registry']->get('settings.cache.memcache.port', 11211)
);
$driver = new DoctrineCache\MemcachedCache();
$driver->setMemcached($memcached);
return $driver;
}
/**
* The WinCacheCache driver uses the wincache_ucache_get, wincache_ucache_exists, etc. functions
* that come with the wincache extension
* http://php.net/manual/en/book.wincache.php
*
* @access protected
*/
protected function setWinCacheDriver()
{
$driver = new DoctrineCache\WinCacheCache();
return $driver;
}
/**
* The ArrayCache driver stores the cache data in PHPs memory and is not persisted anywhere.
* This can be useful for caching things in memory for a single process when you don't need the cache to be persistent across processes.
* @access protected
*/
protected function setArrayCacheDriver()
{
$driver = new DoctrineCache\ArrayCache();
return $driver;
}
/**
* The ApcuCache driver uses the apcu_fetch, apcu_exists, etc. functions
* that come with PHP so no additional setup is required in order to use it.
*
* @access protected
*/
protected function setApcuCacheDriver()
{
$driver = new DoctrineCache\ApcuCache();
return $driver;
}
/**
* The RedisCache driver stores the cache data in Redis and depends on the phpredis extension
* https://github.com/phpredis/phpredis
*
* @access protected
*/
protected function setRedisCacheDriver()
{
$redis = new \Redis();
$socket = $this->flextype['registry']->get('settings.cache.redis.socket', false);
$password = $this->flextype['registry']->get('settings.cache.redis.password', false);
if ($socket) {
$redis->connect($socket);
} else {
$redis->connect(
$this->flextype['registry']->get('settings.cache.redis.server', 'localhost'),
$this->flextype['registry']->get('settings.cache.redis.port', 6379)
);
}
// Authenticate with password if set
if ($password && !$redis->auth($password)) {
throw new \RedisException('Redis authentication failed');
}
$driver = new DoctrineCache\RedisCache();
$driver->setRedis($redis);
return $driver;
}
/**
* Filesystem cache Driver
*
* @access protected
*/
protected function setFilesystemCacheDriver()
{
// Cache directory
$cache_directory = PATH['cache'] . '/doctrine/';
// Create doctrine cache directory if its not exists
!Filesystem::has($cache_directory) and Filesystem::createDir($cache_directory);
$driver = new DoctrineCache\FilesystemCache($cache_directory);
return $driver;
}
/**
* Set Default Cache Driver Name
*
* @access protected
* @param string $driver_name Driver name.
* @return string
*/
protected function setDefaultCacheDriverName(string $driver_name)
{
if (!$driver_name || $driver_name == 'auto') {
if (extension_loaded('apcu')) {
$driver_name = 'apcu';
} elseif (extension_loaded('wincache')) {
$driver_name = 'wincache';
} else {
$driver_name = 'file';
}
}
return $driver_name;
}
/**
* Returns driver variable
*
* @access public
* @return object
*/
public function driver()
{
return $this->driver;
}
/**
* Get cache key.
*
* @access public
* @return string
*/
public function getKey() : string
{
return $this->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(string $id)
{
if ($this->flextype['registry']->get('settings.cache.enabled')) {
return $this->driver->fetch($id);
} else {
return false;
}
}
/**
* Returns a boolean state of whether or not the item exists in the cache based on id key
*
* @param string $id the id of the cached data entry
* @return bool true if the cached items exists
*/
public function contains($id)
{
if ($this->flextype['registry']->get('settings.cache.enabled')) {
return $this->driver->contains($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(string $id, $data, $lifetime = null)
{
if ($this->flextype['registry']->get('settings.cache.enabled')) {
if ($lifetime === null) {
$lifetime = $this->getLifetime();
}
$this->driver->save($id, $data, $lifetime);
}
}
/**
* Clear Cache
*/
public function clear() : void
{
// Clear stat cache
@clearstatcache();
// Clear opcache
function_exists('opcache_reset') and @opcache_reset();
// Remove cache dirs
Filesystem::deleteDir(PATH['cache'] . '/doctrine/');
Filesystem::deleteDir(PATH['cache'] . '/glide/');
}
/**
* Set the cache lifetime.
*
* @access public
* @param int $future timestamp
*/
public function setLifetime(int $future)
{
if (!$future) {
return;
}
$interval = $future-$this->now;
if ($interval > 0 && $interval < $this->getLifetime()) {
$this->lifetime = $interval;
}
}
/**
* Retrieve the cache lifetime (in seconds)
*
* @access public
* @return mixed
*/
public function getLifetime()
{
if ($this->lifetime === null) {
$this->lifetime = $this->flextype['registry']->get('settings.cache.lifetime') ?: 604800;
}
return $this->lifetime;
}
}

View File

@@ -0,0 +1,30 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
class Controller
{
protected $container;
public function __construct($container)
{
$this->container = $container;
}
public function __get($property)
{
if ($this->container->{$property}) {
return $this->container->{$property};
}
}
}

283
flextype/core/Entries.php Executable file
View File

@@ -0,0 +1,283 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
use Flextype\Component\Arr\Arr;
use Flextype\Component\Filesystem\Filesystem;
class Entries
{
/**
* Flextype Dependency Container
*/
private $flextype;
/**
* Constructor
*
* @access public
*/
public function __construct($flextype)
{
$this->flextype = $flextype;
}
/**
* Fetch entry
*
* @access public
* @param string $id Entry id
* @return array|false The entry contents or false on failure.
*/
public function fetch(string $id)
{
$entry_file = $this->_file_location($id);
if (Filesystem::has($entry_file)) {
$cache_id = md5('entry' . $entry_file . ((Filesystem::getTimestamp($entry_file) === false) ? '' : Filesystem::getTimestamp($entry_file)));
// Try to get the entry from cache
if ($this->flextype['cache']->contains($cache_id)) {
if ($entry_decoded = $this->flextype['cache']->fetch($cache_id)) {
// Apply Shortcodes for each entry fields
foreach ($entry_decoded as $key => $_entry_decoded) {
$entry_decoded[$key] = $_entry_decoded;//$this->flextype['shortcodes']->process($_entry_decoded);
}
return $entry_decoded;
} else {
return false;
}
} else {
if ($entry_body = Filesystem::read($entry_file)) {
if ($entry_decoded = JsonParser::decode($entry_body)) {
// Create default entry items
$entry_decoded['date'] = $entry_decoded['date'] ?? date($this->flextype['registry']->get('settings.date_format'), Filesystem::getTimestamp($entry_file));
$entry_decoded['slug'] = $entry_decoded['slug'] ?? ltrim(rtrim($id, '/'), '/');
// Save to cache
$this->flextype['cache']->save($cache_id, $entry_decoded);
// Apply Shortcodes for each entry fields
foreach ($entry_decoded as $key => $_entry_decoded) {
$entry_decoded[$key] = $_entry_decoded;//$this->flextype['shortcodes']->process($_entry_decoded);
}
return $entry_decoded;
} else {
return false;
}
} else {
return false;
}
}
} else {
return false;
}
}
/**
* Fetch all entries
*
* @access public
* @param string $id Entry id
* @param string $order_by Order by specific entry field.
* @param string $order_type Order type: DESC or ASC
* @param int $offset Offset
* @param int $length Length
* @return array The entries
*/
public function fetchAll(string $id, string $order_by = 'date', string $order_type = 'DESC', int $offset = null, int $length = null) : array
{
// Entries array where founded entries will stored
$entries = [];
// Сache id
$cache_id = '';
// Entries path
$entries_path = $this->_dir_location($id);
// Get entries list
$entries_list = Filesystem::listContents($entries_path);
// Create entries cached id
foreach ($entries_list as $current_entry) {
if (strpos($current_entry['path'], $id . '/entry.json') !== false) {
// ignore ...
} else {
if ($current_entry['type'] == 'dir' && Filesystem::has($current_entry['path'] . '/entry.json')) {
$cache_id .= md5('entries' . $current_entry['path'] . Filesystem::getTimestamp($current_entry['path'] . '/entry.json'));
}
}
}
if ($this->flextype['cache']->contains($cache_id)) {
$entries = $this->flextype['cache']->fetch($cache_id);
} else {
// Create entries array from entries list and ignore current requested entry
foreach ($entries_list as $current_entry) {
if (strpos($current_entry['path'], $id . '/entry.json') !== false) {
// ignore ...
} else {
if ($current_entry['type'] == 'dir' && Filesystem::has($current_entry['path'] . '/entry.json')) {
$entries[$current_entry['dirname']] = $this->fetch($id . '/' . $current_entry['dirname']);
}
}
}
$this->flextype['cache']->save($cache_id, $entries);
}
// Sort and Slice entries if $raw === false
if (count($entries) > 0) {
$entries = Arr::sort($entries, $order_by, $order_type);
if ($offset !== null && $length !== null) {
$entries = array_slice($entries, $offset, $length);
}
}
return $entries;
}
/**
* Rename entry.
*
* @access public
* @param string $id Entry id
* @param string $new_id New entry id
* @return bool True on success, false on failure.
*/
public function rename(string $id, string $new_id) : bool
{
return rename($this->_dir_location($id), $this->_dir_location($new_id));
}
/**
* Update entry
*
* @access public
* @param string $id Entry
* @param array $data Data
* @return bool
*/
public function update(string $id, array $data) : bool
{
$entry_file = $this->_file_location($id);
if (Filesystem::has($entry_file)) {
return Filesystem::write($entry_file, JsonParser::encode($data));
} else {
return false;
}
}
/**
* Create entry
*
* @access public
* @param string $id Entry id
* @param array $data Data
* @return bool
*/
public function create(string $id, array $data) : bool
{
$entry_dir = $this->_dir_location($id);
// Check if new entry directory exists
if (!Filesystem::has($entry_dir)) {
// Try to create directory for new entry
if (Filesystem::createDir($entry_dir)) {
$entry_file = $entry_dir . '/entry.json';
// Check if new entry file exists
if (!Filesystem::has($entry_file)) {
return Filesystem::write($entry_file, JsonParser::encode($data));
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
}
/**
* Delete entry.
*
* @access public
* @param string $id Entry id
* @return bool True on success, false on failure.
*/
public function delete(string $id) : bool
{
return Filesystem::deleteDir($this->_dir_location($id));
}
/**
* Copy entry(s)
*
* @access public
* @param string $id Entry id
* @param string $new_id New entry id
* @param bool $recursive Recursive copy entries.
* @return bool True on success, false on failure.
*/
public function copy(string $id, string $new_id, bool $recursive = false)
{
return Filesystem::copy($this->_dir_location($id), $this->_dir_location($new_id), $recursive);
}
/**
* Check whether entry exists.
*
* @access public
* @param string $id Entry
* @return bool
*/
public function has(string $id) : bool
{
return Filesystem::has($this->_file_location($id));
}
/**
* Helper method _file_location
*
* @access private
* @param string $id Entry id
* @return string
*/
private function _file_location(string $id) : string
{
return PATH['entries'] . '/' . $id . '/entry.json';
}
/**
* Helper method _dir_location
*
* @access private
* @param string $id Entry id
* @return string
*/
private function _dir_location(string $id) : string
{
return PATH['entries'] . '/' . $id;
}
}

198
flextype/core/Fieldsets.php Normal file
View File

@@ -0,0 +1,198 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
use Flextype\Component\Filesystem\Filesystem;
class Fieldsets
{
/**
* Flextype Dependency Container
*/
private $flextype;
/**
* Constructor
*
* @access public
*/
public function __construct($flextype)
{
$this->flextype = $flextype;
}
/**
* Fetch fieldset
*
* @access public
* @param string $id Fieldset id
* @return array|false The entry contents or false on failure.
*/
public function fetch(string $id)
{
$fieldset_file = $this->_file_location($id);
if (Filesystem::has($fieldset_file)) {
if ($fieldset_body = Filesystem::read($fieldset_file)) {
if ($fieldset_decoded = JsonParser::decode($fieldset_body)) {
return $fieldset_decoded;
} else {
return false;
}
} else {
return false;
}
} else {
return false;
}
}
/**
* Fetch all fieldsets
*
* @access public
* @return array
*/
public function fetchAll() : array
{
// Init Fieldsets array
$fieldsets = [];
// Get fieldsets files
$_fieldsets = Filesystem::listContents($this->_dir_location());
// If there is any fieldsets file then go...
if (count($_fieldsets) > 0) {
foreach ($_fieldsets as $fieldset) {
if ($fieldset['type'] == 'file' && $fieldset['extension'] == 'json') {
$fieldset_content = JsonParser::decode(Filesystem::read($fieldset['path']));
$fieldsets[$fieldset['basename']] = $fieldset_content['title'];
}
}
}
// return fieldsets array
return $fieldsets;
}
/**
* Rename fieldset
*
* @access public
* @param string $id Fieldset id
* @param string $new_id New fieldset id
* @return bool True on success, false on failure.
*/
public function rename(string $id, string $new_id) : bool
{
return rename($this->_file_location($id), $this->_file_location($new_id));
}
/**
* Update fieldset
*
* @access public
* @param string $id Fieldset id
* @param array $data Fieldset data to save
* @return bool True on success, false on failure.
*/
public function update(string $id, array $data) : bool
{
$fieldset_file = $this->_file_location($id);
if (Filesystem::has($fieldset_file)) {
return Filesystem::write($fieldset_file, JsonParser::encode($data));
} else {
return false;
}
}
/**
* Create fieldset
*
* @access public
* @param string $id Fieldset id
* @param array $data Fieldset data to save
* @return bool True on success, false on failure.
*/
public function create(string $id, array $data) : bool
{
$fieldset_file = $this->_file_location($id);
if (!Filesystem::has($fieldset_file)) {
return Filesystem::write($fieldset_file, JsonParser::encode($data));
} else {
return false;
}
}
/**
* Delete fieldset
*
* @access public
* @param string $id Fieldset id
* @return bool True on success, false on failure.
*/
public function delete(string $id) : bool
{
return Filesystem::delete($this->_file_location($id));
}
/**
* Copy fieldset
*
* @access public
* @param string $id Fieldset id
* @param string $new_id New fieldset id
* @return bool True on success, false on failure.
*/
public function copy(string $id, string $new_id) : bool
{
return Filesystem::copy($this->_file_location($id), $this->_file_location($new_id), false);
}
/**
* Check whether fieldset exists.
*
* @access public
* @param string $id Fieldset id
* @return bool True on success, false on failure.
*/
public function has(string $id) : bool
{
return Filesystem::has($this->_file_location($id));
}
/**
* Helper method _dir_location
*
* @access private
* @return string
*/
private function _dir_location() : string
{
return PATH['site'] . '/fieldsets/';
}
/**
* Helper method _file_location
*
* @access private
* @param string $id Fieldsets id
* @return string
*/
private function _file_location(string $id) : string
{
return PATH['site'] . '/fieldsets/' . $id . '.json';
}
}

View File

@@ -0,0 +1,30 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
class Middleware
{
protected $container;
public function __construct($container)
{
$this->container = $container;
}
public function __get($property)
{
if ($this->container->{$property}) {
return $this->container->{$property};
}
}
}

201
flextype/core/Plugins.php Executable file
View File

@@ -0,0 +1,201 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\I18n\I18n;
use Flextype\Component\Arr\Arr;
class Plugins
{
/**
* Flextype Dependency Container
*/
private $flextype;
/**
* Locales array
*
* @var array
*/
private $locales = [];
/**
* Constructor
*
* @access public
*/
public function __construct($flextype, $app)
{
$this->flextype = $flextype;
$this->locales = JsonParser::decode(Filesystem::read(ROOT_DIR . '/flextype/config/locales.json'));
}
public function getLocales()
{
return $this->locales;
}
/**
* Init Plugins
*
* @access private
* @return void
*/
public function init($flextype, $app) : void
{
// Set empty plugins item
$this->flextype['registry']->set('plugins', []);
// Get Plugins List
$_plugins_list = Filesystem::listContents(PATH['plugins']);
$plugins_list = [];
foreach($_plugins_list as $plugin) {
if ($plugin['type'] == 'dir') {
$plugins_list[] = $plugin;
}
}
// Get plugins cache ID
$plugins_cache_id = $this->getPluginsCacheID($plugins_list);
// If Plugins List isnt empty then create plugin cache ID
if (is_array($plugins_list) && count($plugins_list) > 0) {
// Get plugins list from cache or scan plugins folder and create new plugins cache item
if ($this->flextype['cache']->contains($plugins_cache_id)) {
$this->flextype['registry']->set('plugins', $this->flextype['cache']->fetch($plugins_cache_id));
} else {
// If Plugins List isnt empty
if (is_array($plugins_list) && count($plugins_list) > 0) {
// Init plugin configs
$_plugins_config = [];
$plugin_settings = [];
$plugin_config = [];
// Go through...
foreach ($plugins_list as $plugin) {
if (Filesystem::has($_plugin_settings = PATH['plugins'] . '/' . $plugin['dirname'] . '/settings.json')) {
if (($content = Filesystem::read($_plugin_settings)) === false) {
throw new \RuntimeException('Load file: ' . $_plugin_settings . ' - failed!');
} else {
$plugin_settings = JsonParser::decode($content);
}
}
if (Filesystem::has($_plugin_config = PATH['plugins'] . '/' . $plugin['dirname'] . '/plugin.json')) {
if (($content = Filesystem::read($_plugin_config)) === false) {
throw new \RuntimeException('Load file: ' . $_plugin_config . ' - failed!');
} else {
$plugin_config = JsonParser::decode($content);
}
}
$_plugins_config[$plugin['dirname']] = array_merge($plugin_settings, $plugin_config);
// Set default plugin priority 0
if (!isset($_plugins_config[$plugin['dirname']]['priority'])) {
$_plugins_config[$plugin['dirname']]['priority'] = 0;
}
}
// Sort plugins list by priority.
$_plugins_config = Arr::sort($_plugins_config, 'priority', 'DESC');
$this->flextype['registry']->set('plugins', $_plugins_config);
$this->flextype['cache']->save($plugins_cache_id, $_plugins_config);
}
}
$this->createPluginsDictionary($plugins_list);
$this->includeEnabledPlugins($flextype, $app);
$this->flextype['emitter']->emit('onPluginsInitialized');
}
}
/**
* Create plugins dictionary
*
* @param array $plugins_list Plugins list
* @access protected
* @return void
*/
private function createPluginsDictionary(array $plugins_list) : void
{
if (is_array($plugins_list) && count($plugins_list) > 0) {
foreach ($this->locales as $locale => $locale_title) {
foreach ($plugins_list as $plugin) {
$language_file = PATH['plugins'] . '/' . $plugin['dirname'] . '/lang/' . $locale . '.json';
if (Filesystem::has($language_file)) {
if (($content = Filesystem::read($language_file)) === false) {
throw new \RuntimeException('Load file: ' . $language_file . ' - failed!');
} else {
I18n::add(JsonParser::decode($content), $locale);
}
}
}
}
}
}
/**
* Get plugins cache ID
*
* @param array $plugins_list Plugins list
* @access protected
* @return string
*/
private function getPluginsCacheID(array $plugins_list) : string
{
// Plugin cache id
$_plugins_cache_id = '';
// Go through...
if (is_array($plugins_list) && count($plugins_list) > 0) {
foreach ($plugins_list as $plugin) {
if (Filesystem::has($_plugin_settings = PATH['plugins'] . '/' . $plugin['dirname'] . '/settings.json') and
Filesystem::has($_plugin_config = PATH['plugins'] . '/' . $plugin['dirname'] . '/plugin.json')) {
$_plugins_cache_id .= filemtime($_plugin_settings) . filemtime($_plugin_config);
}
}
}
// Create Unique Cache ID for Plugins
$plugins_cache_id = md5('plugins' . PATH['plugins'] . '/' . $_plugins_cache_id);
// Return plugin cache id
return $plugins_cache_id;
}
/**
* Include enabled plugins
*
* @access protected
* @return void
*/
private function includeEnabledPlugins($flextype, $app) : void
{
if (is_array($this->flextype['registry']->get('plugins')) && count($this->flextype['registry']->get('plugins')) > 0) {
foreach ($this->flextype['registry']->get('plugins') as $plugin_name => $plugin) {
if ($this->flextype['registry']->get('plugins.' . $plugin_name . '.enabled')) {
include_once PATH['plugins'] . '/' . $plugin_name . '/bootstrap.php';
}
}
}
}
}

241
flextype/core/Snippets.php Normal file
View File

@@ -0,0 +1,241 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
use Flextype\Component\Filesystem\Filesystem;
class Snippets
{
/**
* Flextype Dependency Container
*/
private $flextype;
/**
* Constructor
*
* @access public
*/
public function __construct($flextype)
{
$this->flextype = $flextype;
}
/**
* Get snippet
*
* @access public
* @param string $id Snippet id
* @return string|bool Returns the contents of the output buffer and end output buffering.
* If output buffering isn't active then FALSE is returned.
*/
public function display(string $id)
{
return $this->_display_snippet(['fetch' => $id]);
}
/**
* Fetch snippet
*
* @access public
* @param string $id Snippet id
* @return array|false The entry contents or false on failure.
*/
public function fetch(string $id)
{
$snippet_file = $this->_file_location($id);
if (Filesystem::has($snippet_file)) {
if ($snippet_body = Filesystem::read($snippet_file)) {
return $snippet_body;
} else {
return false;
}
} else {
return false;
}
}
/**
* Fetch Snippets
*
* @access public
* @return array
*/
public function fetchAll() : array
{
$snippets = [];
// Get snippets files
$_snippets = Filesystem::listContents($this->_dir_location());
// If there is any snippets file then go...
if (count($_snippets) > 0) {
foreach ($_snippets as $snippet) {
if ($snippet['type'] == 'file' && $snippet['extension'] == 'php') {
$snippets[$snippet['basename']] = $snippet['basename'];
}
}
}
// return snippets
return $snippets;
}
/**
* Rename snippet.
*
* @access public
* @param string $id Snippet id
* @param string $new_id New snippet id
* @return bool True on success, false on failure.
*/
public function rename(string $id, string $new_id) : bool
{
return rename($this->_file_location($id), $this->_file_location($new_id));
}
/**
* Update Snippet
*
* @access public
* @param string $id Snippet id
* @param string $data Data
* @return bool True on success, false on failure.
*/
public function update(string $id, string $data) : bool
{
$snippet_file = $this->_file_location($id);
if (Filesystem::has($snippet_file)) {
return Filesystem::write($snippet_file, $data);
} else {
return false;
}
}
/**
* Create snippet
*
* @access public
* @param string $id Snippet id
* @param string $data Data
* @return bool True on success, false on failure.
*/
public function create(string $id, string $data = '') : bool
{
$snippet_file = $this->_file_location($id);
// Check if new entry file exists
if (!Filesystem::has($snippet_file)) {
return Filesystem::write($snippet_file, $data);
} else {
return false;
}
}
/**
* Delete snippet.
*
* @access public
* @param string $id Snippet id
* @return bool True on success, false on failure.
*/
public function delete(string $id) : bool
{
return Filesystem::delete($this->_file_location($id));
}
/**
* Copy snippet
*
* @access public
* @param string $id Snippet id
* @param string $new_id New snippet id
* @return bool True on success, false on failure.
*/
public function copy(string $id, string $new_id) : bool
{
return Filesystem::copy($this->_file_location($id), $this->_file_location($new_id), false);
}
/**
* Check whether snippet exists.
*
* @access public
* @param string $id Snippet id
* @return bool True on success, false on failure.
*/
public function has(string $id) : bool
{
return Filesystem::has($this->_file_location($id));
}
/**
* Helper private method _display_snippet
*
* @access private
* @param array $vars Vars
* @return string|bool Returns the contents of the output buffer and end output buffering.
* If output buffering isn't active then FALSE is returned.
*/
private function _display_snippet(array $vars)
{
// Extracst attributes
extract($vars);
// Get snippet name
$name = (isset($fetch)) ? (string) $fetch : '';
// Define snippet path
$snippet_file = $this->_file_location($name);
// Process snippet
if (Filesystem::has($snippet_file)) {
// Turn on output buffering
ob_start();
// Include view file
include $snippet_file;
// Output...
return ob_get_clean();
} else {
throw new \RuntimeException("Snippet {$name} does not exist.");
}
}
/**
* Helper method _file_location
*
* @access private
* @param string $id Snippet id
* @return string
*/
private function _file_location(string $id) : string
{
return PATH['snippets'] . '/' . $id . '.php';
}
/**
* Helper method _dir_location
*
* @access private
* @return string
*/
private function _dir_location() : string
{
return PATH['snippets'] . '/';
}
}

114
flextype/core/Themes.php Normal file
View File

@@ -0,0 +1,114 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
use Flextype\Component\Filesystem\Filesystem;
class Themes
{
/**
* Flextype Dependency Container
*/
private $flextype;
/**
* Private construct method to enforce singleton behavior.
*
* @access private
*/
public function __construct($flextype)
{
$this->flextype = $flextype;
}
public function init($flextype, $app)
{
// Get current theme
$theme = $this->flextype['registry']->get('settings.theme');
// Set empty themes items
$this->flextype['registry']->set('themes', []);
// Create Unique Cache ID for Theme
$theme_cache_id = md5('theme' . filemtime(PATH['themes'] . '/' . $theme . '/' . 'settings.json') .
filemtime(PATH['themes'] . '/' . $theme . '/' . 'theme.json'));
// Get Theme mafifest file and write to settings.themes array
if ($this->flextype['cache']->contains($theme_cache_id)) {
$this->flextype['registry']->set('themes.' . $this->flextype['registry']->get('settings.theme'), $this->flextype['cache']->fetch($theme_cache_id));
} else {
if (Filesystem::has($theme_settings = PATH['themes'] . '/' . $theme . '/' . 'settings.json') and
Filesystem::has($theme_config = PATH['themes'] . '/' . $theme . '/' . 'theme.json')) {
$theme_settings = JsonParser::decode(Filesystem::read($theme_settings));
$theme_config = JsonParser::decode(Filesystem::read($theme_config));
$_theme = array_merge($theme_settings, $theme_config);
$this->flextype['registry']->set('themes.' . $this->flextype['registry']->get('settings.theme'), $_theme);
$this->flextype['cache']->save($theme_cache_id, $_theme);
}
}
}
/**
* Get partials for current theme
*
* @access public
* @return array
*/
public function getPartials() : array
{
$partials = [];
// Get partials files
$_partials = Filesystem::listContents(PATH['themes'] . '/' . $this->flextype['registry']->get('settings.theme') . '/templates/partials/');
// If there is any partials file then go...
if (count($_partials) > 0) {
foreach ($_partials as $partial) {
if ($partial['type'] == 'file' && $partial['extension'] == 'html') {
$partials[$partial['basename']] = $partial['basename'];
}
}
}
// return partials
return $partials;
}
/**
* Get templates for current theme
*
* @access public
* @return array
*/
public function getTemplates() : array
{
$templates = [];
// Get templates files
$_templates = Filesystem::listContents(PATH['themes'] . '/' . $this->flextype['registry']->get('settings.theme') . '/templates/');
// If there is any template file then go...
if (count($_templates) > 0) {
foreach ($_templates as $template) {
if ($template['type'] == 'file' && $template['extension'] == 'html') {
$templates[$template['basename']] = $template['basename'];
}
}
}
// return templates
return $templates;
}
}

231
flextype/dependencies.php Normal file
View File

@@ -0,0 +1,231 @@
<?php
/**
* @package Flextype
*
* @author Romanenko Sergey <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
use Flextype\Component\Registry\Registry;
use Thunder\Shortcode\ShortcodeFacade;
use Slim\Flash\Messages;
use Cocur\Slugify\Slugify;
use League\Glide\ServerFactory;
use League\Glide\Responses\SlimResponseFactory;
use League\Event\Emitter;
/**
* Add CSRF (cross-site request forgery) protection service to Flextype container
*/
$flextype['csrf'] = function ($container) {
return new \Slim\Csrf\Guard;
};
/**
* Add logger
*/
$flextype['logger'] = function($container) {
$logger = new \Monolog\Logger('flextype');
$file_handler = new \Monolog\Handler\StreamHandler(PATH['site'] . '/logs/' . date('Y-m-d') . '.log');
$logger->pushHandler($file_handler);
return $logger;
};
/**
* Add emitter service to Flextype container
*/
$flextype['emitter'] = function ($container) {
return new Emitter();
};
/**
* Add slugify service to Flextype container
*/
$flextype['slugify'] = function ($container) {
return new Slugify(['separator' => '-', 'lowercase' => true, 'trim' => true]);
};
/**
* Add flash service to Flextype container
*/
$flextype['flash'] = function ($container) {
return new Messages();
};
/**
* Add registry service to Flextype container
*/
$flextype['registry'] = function ($container) {
return new Registry();
};
/**
* Add cache service to Flextype container
*/
$flextype['cache'] = function ($container) use ($flextype) {
return new Cache($flextype);
};
/**
* Add images service to Flextype container
*/
$flextype['images'] = function ($container) {
// Get images settings
$imagesSettings = $container->get('settings')['images'];
// Set source filesystem
$source = new \League\Flysystem\Filesystem(
new \League\Flysystem\Adapter\Local(PATH['entries'])
);
// Set cache filesystem
$cache = new \League\Flysystem\Filesystem(
new \League\Flysystem\Adapter\Local(PATH['cache'] . '/glide')
);
// Set watermarks filesystem
$watermarks = new \League\Flysystem\Filesystem(
new \League\Flysystem\Adapter\Local(PATH['site'] . '/watermarks')
);
// Set image manager
$imageManager = new \Intervention\Image\ImageManager($imagesSettings);
// Set manipulators
$manipulators = [
new \League\Glide\Manipulators\Orientation(),
new \League\Glide\Manipulators\Crop(),
new \League\Glide\Manipulators\Size(2000*2000),
new \League\Glide\Manipulators\Brightness(),
new \League\Glide\Manipulators\Contrast(),
new \League\Glide\Manipulators\Gamma(),
new \League\Glide\Manipulators\Sharpen(),
new \League\Glide\Manipulators\Filter(),
new \League\Glide\Manipulators\Blur(),
new \League\Glide\Manipulators\Pixelate(),
new \League\Glide\Manipulators\Watermark($watermarks),
new \League\Glide\Manipulators\Background(),
new \League\Glide\Manipulators\Border(),
new \League\Glide\Manipulators\Encode(),
];
// Set API
$api = new \League\Glide\Api\Api($imageManager, $manipulators);
// Setup Glide server
$server = \League\Glide\ServerFactory::create([
'source' => $source,
'cache' => $cache,
'api' => $api,
'response' => new SlimResponseFactory(),
]);
return $server;
};
/**
* Add fieldsets service to Flextype container
*/
$flextype['fieldsets'] = function ($container) use ($flextype) {
return new Fieldsets($flextype);
};
/**
* Add snippets service to Flextype container
*/
$flextype['snippets'] = function ($container) use ($flextype) {
return new Snippets($flextype);
};
/**
* Add shortcodes service to Flextype container
*/
$flextype['shortcodes'] = function ($container) {
return new ShortcodeFacade();
};
/**
* Add entries service to Flextype container
*/
$flextype['entries'] = function ($container) {
return new Entries($container);
};
/**
* Add view service to Flextype container
*/
$flextype['view'] = function ($container) {
// Get twig settings
$twigSettings = $container->get('settings')['twig'];
// Create Twig View
$view = new \Slim\Views\Twig(PATH['site'], $twigSettings);
// Instantiate
$router = $container->get('router');
$uri = \Slim\Http\Uri::createFromEnvironment(new \Slim\Http\Environment($_SERVER));
// Add Twig Extension
$view->addExtension(new \Slim\Views\TwigExtension($router, $uri));
// Add Twig Debug Extension
$view->addExtension(new \Twig\Extension\DebugExtension());
// Add Entries Twig Extension
$view->addExtension(new EntriesTwigExtension($container));
// Add Emitter Twig Extension
$view->addExtension(new EmitterTwigExtension($container));
// Add Flash Twig Extension
$view->addExtension(new FlashTwigExtension($container));
// Add I18n Twig Extension
$view->addExtension(new I18nTwigExtension());
// Add JsonParser Extension
$view->addExtension(new JsonParserTwigExtension());
// Add Filesystem Extension
$view->addExtension(new FilesystemTwigExtension());
// Add Assets Twig Extension
$view->addExtension(new AssetsTwigExtension());
// Add Csrf Twig Extension
$view->addExtension(new CsrfTwigExtension($container->get('csrf')));
// Add Global Vars Twig Extension
$view->addExtension(new GlobalVarsTwigExtension($container));
// Add Global Shortcodes Twig Extension
$view->addExtension(new ShortcodesTwigExtension($container));
// Add Global Snippets Twig Extension
$view->addExtension(new SnippetsTwigExtension($container));
// Return view
return $view;
};
/**
* Add themes service to Flextype container
*/
$flextype['themes'] = function ($container) use ($flextype, $app) {
return new Themes($flextype, $app);
};
/**
* Add plugins service to Flextype container
*/
$flextype['plugins'] = function ($container) use ($flextype, $app) {
return new Plugins($flextype, $app);
};

26
flextype/middlewares.php Normal file
View File

@@ -0,0 +1,26 @@
<?php
/**
* @package Flextype
*
* @author Romanenko Sergey <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
use Psr7Middlewares\Middleware;
use Psr7Middlewares\Middleware\TrailingSlash;
/**
* Add middleware CSRF (cross-site request forgery) protection for all routes
*/
$app->add($flextype->get('csrf'));
/**
* Add middleware TrailingSlash for all routes
*/
$app->add((new TrailingSlash(false))->redirect(301));

View File

@@ -0,0 +1,119 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
class JsonParser
{
/**
* Encode options
*
* Bitmask consisting of encode options
* https://www.php.net/manual/en/function.json-encode.php
*
* @var int
*/
public static $encode_options = JSON_UNESCAPED_UNICODE|JSON_UNESCAPED_SLASHES|JSON_PRETTY_PRINT;
/**
* Encode Depth
*
* Set the maximum depth.
*
* @var int
*/
public static $encode_depth = 512;
/**
* Decode assoc
*
* Set the maximum depth.
*
* @var int
*/
public static $decode_assoc = true;
/**
* Decode Depth
*
* Set the maximum depth.
*
* @var int
*/
public static $decode_depth = 512;
/**
* Decode options
*
* Bitmask consisting of decode options
* https://www.php.net/manual/en/function.json-decode.php
*
* @var int
*/
public static $decode_options = 0;
/**
* Returns the JSON representation of a value
*
* $result = JsonParser::encode($json_content);
*
* @param mixed $input A string containing JSON
* @param int $encode_depth User specified recursion depth.
* @param int $encode_options Bitmask consisting of encode options.
* @return mixed The JSON converted to a PHP value
*
*/
public static function encode($input, int $encode_options = 0, int $encode_depth = 512) : string
{
$encoded = @json_encode(
$input,
$encode_options ? $encode_options : JsonParser::$encode_options,
$encode_depth ? $encode_depth : JsonParser::$encode_depth
);
if ($encoded === false) {
throw new \RuntimeException('Encoding JSON failed');
}
return $encoded;
}
/**
* Takes a JSON encoded string and converts it into a PHP variable.
*
* $array = JsonParser::decode($json_file_content);
*
* @param string $input A string containing JSON
* @param bool $decode_assoc When TRUE, returned objects will be converted into associative arrays.
* @param int $decode_depth User specified recursion depth.
* @param int $decode_options Bitmask consisting of decode options.
* @return mixed The JSON converted to a PHP value
*
* @throws ParseException If the JSON is not valid
*/
public static function decode(string $input, bool $decode_assoc = true, int $decode_depth = 512, int $decode_options = 0)
{
$decoded = @json_decode(
$input,
$decode_assoc ? $decode_assoc : JsonParser::$decode_assoc,
$decode_depth ? $decode_depth : JsonParser::$decode_depth,
$decode_options ? $decode_options : JsonParser::$decode_options
);
if ($decoded === false) {
throw new \RuntimeException('Decoding JSON failed');
}
return $decoded;
}
}

View File

@@ -1,118 +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;
use Symfony\Component\Yaml\Exception\DumpException;
use Symfony\Component\Yaml\Exception\ParseException;
class YamlParser {
/**
* Inline
*
* The level where you switch to inline YAML
*
* @var int
*/
public static $inline = 5;
/**
* Ident
*
* The amount of spaces to use for indentation of nested nodes
*
* @var int
*/
public static $indent = 2;
/**
* Native
*
* Use native parser or symfony
*
* @var bool
*/
public static $native = true;
/**
* Flag
*
* A bit field of PARSE_* constants to customize the YAML parser behavior
*
* @var int
*/
public static $flag = 16;
/**
* Dumps a PHP value to a YAML string.
*
* The dump method, when supplied with an array, will do its best
* to convert the array into friendly YAML.
*
* @param mixed $input The PHP value
* @param int $inline The level where you switch to inline YAML
* @param int $indent The amount of spaces to use for indentation of nested nodes
* @param int $flags A bit field of DUMP_* constants to customize the dumped YAML string
*
* @return string A YAML string representing the original PHP value
*/
public static function encode($input, int $inline = 5, int $indent = 2, int $flags = 16) : string
{
try {
return Yaml::dump(
$input,
$inline ? $inline : YamlParser::$inline,
$indent ? $indent : YamlParser::$indent,
$flags ? $flags : YamlParser::$flag
);
} catch (DumpException $e) {
throw new \RuntimeException('Encoding YAML failed: ' . $e->getMessage(), 0, $e);
}
}
/**
* Parses YAML into a PHP value.
*
* $array = YamlParser::decode($yaml_file_content);
*
* @param string $input A string containing YAML
* @param int $flags A bit field of PARSE_* constants to customize the YAML parser behavior
*
* @return mixed The YAML converted to a PHP value
*
* @throws ParseException If the YAML is not valid
*/
public static function decode(string $input, int $flags = 0)
{
// Try native PECL YAML PHP extension first if available.
if (YamlParser::$native && function_exists('yaml_parse')) {
// Safely decode YAML.
$saved = @ini_get('yaml.decode_php');
@ini_set('yaml.decode_php', 0);
$decoded = @yaml_parse($input);
@ini_set('yaml.decode_php', $saved);
if ($decoded !== false) {
return (array) $decoded;
}
}
try {
return (array) Yaml::parse($input);
} catch (ParseException $e) {
throw new \RuntimeException('Decoding YAML failed: ' . $e->getMessage(), 0, $e);
}
}
}

13
flextype/routes/web.php Normal file
View File

@@ -0,0 +1,13 @@
<?php
namespace Flextype;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
/**
* Generates and returns the image response
*/
$app->get('/image/{path:.+}', function (Request $request, Response $response, array $args) use ($flextype) {
return $flextype['images']->getImageResponse($args['path'], $_GET);
});

View File

@@ -0,0 +1,21 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
use Thunder\Shortcode\ShortcodeFacade;
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
// Shortcode: [site_url]
$flextype['shortcodes']->addHandler('site_url', function () {
return \Slim\Http\Uri::createFromEnvironment(new \Slim\Http\Environment($_SERVER))->getBaseUrl();
});

View File

@@ -0,0 +1,21 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
use Thunder\Shortcode\ShortcodeFacade;
use Thunder\Shortcode\Shortcode\ShortcodeInterface;
// Shortcode: [snippets fetch=snippet-name]
$flextype['shortcodes']->addHandler('snippets', function (ShortcodeInterface $s) use ($flextype) {
return $flextype['snippets']->display($s->getParameter('fetch'));
});

View File

@@ -0,0 +1,41 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
use Flextype\Component\Assets\Assets;
class AssetsTwigExtension extends \Twig_Extension
{
/**
* Callback for twig.
*
* @return array
*/
public function getFunctions()
{
return [
new \Twig_SimpleFunction('assets_add', [$this, 'add']),
new \Twig_SimpleFunction('assets_get', [$this, 'get']),
];
}
public function add(string $asset_type, string $asset, string $namespace, int $priority = 1) : void
{
Assets::add($asset_type, $asset, $namespace, $priority);
}
public function get(string $asset_type, string $namespace) : array
{
return Assets::get($asset_type, $namespace);
}
}

View File

@@ -0,0 +1,75 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
class CsrfTwigExtension extends \Twig_Extension implements \Twig_Extension_GlobalsInterface
{
/**
* @var \Slim\Csrf\Guard
*/
protected $csrf;
public function __construct(\Slim\Csrf\Guard $csrf)
{
$this->csrf = $csrf;
}
public function getGlobals()
{
// CSRF token name and value
$csrfNameKey = $this->csrf->getTokenNameKey();
$csrfValueKey = $this->csrf->getTokenValueKey();
$csrfName = $this->csrf->getTokenName();
$csrfValue = $this->csrf->getTokenValue();
return [
'csrf' => [
'keys' => [
'name' => $csrfNameKey,
'value' => $csrfValueKey
],
'name' => $csrfName,
'value' => $csrfValue
]
];
}
public function getName()
{
return 'slim/csrf';
}
/**
* Callback for twig.
*
* @return array
*/
public function getFunctions()
{
return [
new \Twig_SimpleFunction('csrf', [$this, 'csrf'], ['is_safe' => ['html']]),
];
}
/**
* CSRF
*
* @return string
*/
public function csrf()
{
return '<input type="hidden" name="'.$this->csrf->getTokenNameKey().'" value="'.$this->csrf->getTokenName().'">'.
'<input type="hidden" name="'.$this->csrf->getTokenValueKey().'" value="'.$this->csrf->getTokenValue().'">';
}
}

View File

@@ -0,0 +1,46 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
class EmitterTwigExtension extends \Twig_Extension
{
/**
* Flextype Dependency Container
*/
private $flextype;
/**
* Constructor
*/
public function __construct($flextype)
{
$this->flextype = $flextype;
}
/**
* Callback for twig.
*
* @return array
*/
public function getFunctions()
{
return [
new \Twig_SimpleFunction('emmiter_emmit', [$this, 'emit']),
];
}
public function emit(string $event)
{
$this->flextype['emitter']->emit($event);
}
}

View File

@@ -0,0 +1,52 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
class EntriesTwigExtension extends \Twig_Extension
{
/**
* Flextype Dependency Container
*/
private $flextype;
/**
* Constructor
*/
public function __construct($flextype)
{
$this->flextype = $flextype;
}
/**
* Callback for twig.
*
* @return array
*/
public function getFunctions()
{
return [
new \Twig_SimpleFunction('entries_fetch', [$this, 'fetch']),
new \Twig_SimpleFunction('entries_fetch_all', [$this, 'fetchAll']),
];
}
public function fetch(string $entry)
{
return $this->flextype['entries']->fetch($entry);
}
public function fetchAll(string $entry, string $order_by = 'date', string $order_type = 'DESC', int $offset = null, int $length = null) : array
{
return $this->flextype['entries']->fetchAll($entry, $order_by, $order_type, $offset, $length);
}
}

View File

@@ -0,0 +1,53 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
use Flextype\Component\Filesystem\Filesystem;
class FilesystemTwigExtension extends \Twig_Extension
{
/**
* Callback for twig.
*
* @return array
*/
public function getFunctions()
{
return [
new \Twig_SimpleFunction('filesystem_has', [$this, 'has']),
new \Twig_SimpleFunction('filesystem_read', [$this, 'read']),
new \Twig_SimpleFunction('filesystem_ext', [$this, 'ext']),
new \Twig_SimpleFunction('filesystem_basename', [$this, 'basename']),
];
}
public function has($path)
{
return Filesystem::has($path);
}
public function read($path)
{
return Filesystem::read($path);
}
public function ext($file)
{
return substr(strrchr($file, '.'), 1);
}
public function basename($value, $suffix = '')
{
return basename($value, $suffix);
}
}

View File

@@ -0,0 +1,59 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
use Slim\Flash\Messages;
class FlashTwigExtension extends \Twig_Extension
{
/**
* Flextype Dependency Container
*/
private $flextype;
/**
* Constructor
*/
public function __construct($flextype)
{
$this->flextype = $flextype;
}
/**
* Callback for twig.
*
* @return array
*/
public function getFunctions() : array
{
return [
new \Twig_SimpleFunction('flash', [$this, 'getMessages']),
];
}
/**
* Returns Flash messages; If key is provided then returns messages
* for that key.
*
* @param string $key
* @return array
*/
public function getMessages($key = null) : array
{
if (null !== $key) {
return $this->flextype['flash']->getMessage($key);
}
return $this->flextype['flash']->getMessages();
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
use Flextype\Component\Session\Session;
class GlobalVarsTwigExtension extends \Twig_Extension implements \Twig_Extension_GlobalsInterface
{
/**
* Flextype Dependency Container
*/
private $flextype;
/**
* Constructor
*/
public function __construct($flextype)
{
$this->flextype = $flextype;
}
public function getGlobals()
{
return [
'PATH_SITE' => PATH['site'],
'PATH_PLUGINS' => PATH['plugins'],
'PATH_THEMES' => PATH['themes'],
'PATH_ENTRIES' => PATH['entries'],
'PATH_SNIPPETS' => PATH['snippets'],
'PATH_CONFIG_DEFAULT' => PATH['config']['default'],
'PATH_CONFIG_SITE' => PATH['config']['site'],
'PATH_CACHE' => PATH['cache'],
'flextype_version' => FLEXTYPE_VERSION,
'registry' => $this->flextype['registry']->dump()
];
}
}

View File

@@ -0,0 +1,35 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
use Flextype\Component\I18n\I18n;
class I18nTwigExtension extends \Twig_Extension
{
/**
* Callback for twig.
*
* @return array
*/
public function getFunctions()
{
return [
new \Twig_SimpleFunction('tr', [$this, 'tr']),
];
}
public function tr(string $translate, string $locale = null, array $values = []) : string
{
return I18n::find($translate, $locale, $values);
}
}

View File

@@ -0,0 +1,39 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
class JsonParserTwigExtension extends \Twig_Extension
{
/**
* Callback for twig.
*
* @return array
*/
public function getFunctions()
{
return [
new \Twig_SimpleFunction('json_parser_decode', [$this, 'decode']),
new \Twig_SimpleFunction('json_parser_encode', [$this, 'encode'])
];
}
public function encode($input, int $encode_options = 0, int $encode_depth = 512) : string
{
return JsonParser::encode($input, $encode_options, $encode_depth);
}
public function decode(string $input, bool $decode_assoc = true, int $decode_depth = 512, int $decode_options = 0)
{
return JsonParser::decode($input, $decode_assoc, $decode_depth, $decode_options);
}
}

View File

@@ -0,0 +1,47 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
class ShortcodesTwigExtension extends \Twig_Extension
{
/**
* Flextype Dependency Container
*/
private $flextype;
/**
* Constructor
*/
public function __construct($flextype)
{
$this->flextype = $flextype;
}
/**
* Callback for twig.
*
* @return array
*/
public function getFilters()
{
return [
new \Twig_SimpleFilter('shortcode', [$this, 'shortcode']),
];
}
public function shortcode(string $value) : string
{
return $this->flextype->shortcodes->process($value);
}
}

View File

@@ -0,0 +1,46 @@
<?php
/**
* @package Flextype
*
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Flextype;
class SnippetsTwigExtension extends \Twig_Extension
{
/**
* Flextype Dependency Container
*/
private $flextype;
/**
* Constructor
*/
public function __construct($flextype)
{
$this->flextype = $flextype;
}
/**
* Callback for twig.
*
* @return array
*/
public function getFunctions()
{
return [
new \Twig_SimpleFunction('snippet', [$this, 'snippet'])
];
}
public function snippet(string $id)
{
return $this->flextype['snippets']->display($id);
}
}

View File

@@ -3,8 +3,8 @@
/**
* @package Flextype
*
* @author Sergey Romanenko <awilum@yandex.ru>
* @link http://flextype.org
* @author Sergey Romanenko <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -12,36 +12,57 @@
namespace Flextype;
// Define the application minimum supported PHP version.
/**
* Define the application minimum supported PHP version.
*/
define('FLEXTYPE_MINIMUM_PHP', '7.1.3');
// Define the path to the root directory (without trailing slash).
/**
* Define the PATH to the root directory (without trailing slash).
*/
define('ROOT_DIR', str_replace(DIRECTORY_SEPARATOR, '/', getcwd()));
// Define the PATH (without trailing slash).
define('PATH', ['site' => ROOT_DIR . '/site',
'plugins' => ROOT_DIR . '/site/plugins',
'themes' => ROOT_DIR . '/site/themes',
'entries' => ROOT_DIR . '/site/entries',
'snippets' => ROOT_DIR . '/site/snippets',
'menus' => ROOT_DIR . '/site/menus',
'config' => [
/**
* Define the PATH (without trailing slash).
*/
define('PATH', ['site' => ROOT_DIR . '/site',
'plugins' => ROOT_DIR . '/site/plugins',
'themes' => ROOT_DIR . '/site/themes',
'entries' => ROOT_DIR . '/site/entries',
'snippets' => ROOT_DIR . '/site/snippets',
'fieldsets' => ROOT_DIR . '/site/fieldsets',
'config' => [
'default' => ROOT_DIR . '/flextype/config',
'site' => ROOT_DIR . '/site/config'
],
'cache' => ROOT_DIR . '/site/cache']);
],
'cache' => ROOT_DIR . '/site/cache']);
// Define the path to the logs directory (without trailing slash).
define('LOGS_PATH', PATH['site'] . '/logs');
// Check PHP Version
/**
* Check PHP Version
*/
version_compare($ver = PHP_VERSION, $req = FLEXTYPE_MINIMUM_PHP, '<') and exit(sprintf('You are running PHP %s, but Flextype needs at least <strong>PHP %s</strong> to run.', $ver, $req));
// Ensure vendor libraries exist
/**
* Ensure vendor libraries exist
*/
!is_file($autoload = __DIR__ . '/vendor/autoload.php') and exit("Please run: <i>composer install</i>");
// Register The Auto Loader
/**
* Register The Auto Loader
*
* Composer provides a convenient, automatically generated class loader for
* our application. We just need to utilize it! We'll simply require it
* into the script here so that we don't have to worry about manual
* loading any of our classes later on. It feels nice to relax.
* Register The Auto Loader
*/
$loader = require_once $autoload;
// Get Flextype Instance
$flextype = Flextype::getInstance();
/**
* Bootstraps the Flextype
*
* This bootstraps the Flextype and gets it ready for use, then it
* will load up this application so that we can run it and send
* the responses back to the browser and delight our users.
*/
include 'flextype/bootstrap.php';

View File

0
site/cache/.gitkeep vendored
View File

View File

@@ -0,0 +1 @@
{}

View File

@@ -1,10 +0,0 @@
---
title: About
image: lilia.jpg
template: about
fieldset: about
date: 'December 26 2018 10:26:04'
---
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>

View File

@@ -0,0 +1,13 @@
{
"title": "About",
"image": "lilia.jpg",
"template": "about",
"fieldset": "about",
"content": "<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>\r\n<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>\r\n",
"date": "June 07 2019 10:08:11",
"description": "",
"menu_item_title": "About",
"menu_item_url": "about",
"menu_item_target": "self",
"menu_item_order": "3"
}

View File

@@ -1,24 +0,0 @@
---
title: 'Allamco laboris nisi ut aliquip nisi ut aliquip'
summary: '<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>'
template: blog-post
fieldset: blog-post
date: 'December 25 2018 23:16:47'
---
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<br>
<p>
<img src="https://pp.userapi.com/c846416/v846416486/1188f2/Ob4Xk_yQclo.jpg" alt="">
<br>
</p>
<br>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<br>
<p>
<img src="https://pp.userapi.com/c852232/v852232861/2d7e5/qD2cprowsVg.jpg" alt="">
<br>
</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
<br>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>

File diff suppressed because one or more lines are too long

View File

@@ -1,9 +0,0 @@
---
title: 'Cillum dolore eu fugiat nulla pariatur'
summary: '<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>'
template: blog-post
fieldset: blog-post
date: 'December 25 2018 23:13:53'
---
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>

View File

@@ -0,0 +1,8 @@
{
"title": "Cillum dolore eu fugiat nulla pariatur",
"summary": "<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>",
"template": "blog-post",
"fieldset": "blog-post",
"content": "<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>\n",
"date": "June 06 2019 22:08:11"
}

View File

@@ -1,6 +0,0 @@
---
title: Blog
template: blog
fieldset: blog
date: 'December 25 2018 22:27:15'
---

View File

@@ -0,0 +1,11 @@
{
"title": "Blog",
"template": "blog",
"fieldset": "blog",
"date": "June 07 2019 10:08:11",
"description": "",
"menu_item_title": "Blog",
"menu_item_url": "blog",
"menu_item_target": "self",
"menu_item_order": "2"
}

View File

@@ -1,9 +0,0 @@
---
title: 'Excepteur sint occaecat cupidatat non proident'
summary: '<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>'
template: blog-post
fieldset: blog-post
date: 'December 25 2018 22:57:55'
---
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>

View File

@@ -0,0 +1,8 @@
{
"title": "Excepteur sint occaecat cupidatat non proident",
"summary": "<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>",
"template": "blog-post",
"fieldset": "blog-post",
"content": "<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>\n",
"date": "June 06 2019 22:08:11"
}

View File

@@ -1,9 +0,0 @@
---
title: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit'
summary: '<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>'
template: blog-post
fieldset: blog-post
date: 'December 25 2018 22:50:01'
---
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>

View File

@@ -0,0 +1,8 @@
{
"title": "Lorem ipsum dolor sit amet, consectetur adipisicing elit",
"summary": "<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>",
"template": "blog-post",
"fieldset": "blog-post",
"content": "<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>\n",
"date": "June 06 2019 22:08:11"
}

View File

@@ -1,9 +0,0 @@
---
title: 'Ullamco laboris nisi ut aliquip'
summary: '<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>'
template: blog-post
fieldset: blog-post
date: 'December 25 2018 23:14:49'
---
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>

View File

@@ -0,0 +1,8 @@
{
"title": "Ullamco laboris nisi ut aliquip",
"summary": "<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>",
"template": "blog-post",
"fieldset": "blog-post",
"content": "<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>\n",
"date": "June 06 2019 22:08:11"
}

View File

@@ -1,17 +0,0 @@
---
title: Home
template: home
visibility: visible
date: 'December 25 2018 23:46:58'
fieldset: default
---
<h1 style="text-align: center;">
Welcome!
</h1>
<p style="text-align: center;" class="lead">
Welcome to your new Flextype powered website.
<br>
Flextype is succesfully installed, you can start editing the content and customising your site in <a href="./admin">Admin panel</a>.
</p>
<br>
<p style="text-align: center;">Latest blog posts:</p>

View File

@@ -0,0 +1,13 @@
{
"title": "Home",
"content": "<h1 style=\"text-align: center;\">\r\n Welcome!\r\n</h1>\r\n<p style=\"text-align: center;\" class=\"lead\">\r\n Welcome to your new Flextype powered website.\r\n <br>\r\n Flextype is succesfully installed, you can start editing the content and customising your site in <a href=\"./admin\">Admin panel</a>.\r\n</p>\r\n<br>\r\n<p style=\"text-align: center;\">Latest blog posts:</p>\r\n",
"template": "home",
"fieldset": "default",
"visibility": "visible",
"date": "February 20 2019 11:06:46",
"description": "",
"menu_item_title": "Home",
"menu_item_url": "home",
"menu_item_target": "self",
"menu_item_order": "1"
}

67
site/fieldsets/about.json Normal file
View File

@@ -0,0 +1,67 @@
{
"title": "About",
"default_field": "title",
"sections": {
"main": {
"title": "Main",
"fields": {
"title": {
"title": "admin_title",
"type": "text",
"size": "col-12"
},
"content": {
"title": "admin_content",
"type": "editor",
"size": "col-12"
},
"image": {
"title": "admin_media",
"type": "media_select",
"size": "col-3"
}
}
},
"seo": {
"title": "Seo",
"fields": {
"description": {
"title": "admin_description",
"type": "textarea",
"size": "col-12"
}
}
},
"menu": {
"title": "Menu",
"fields": {
"menu_item_title": {
"title": "admin_menu_item_title",
"type": "text",
"size": "col-4"
},
"menu_item_url": {
"title": "admin_menu_item_url",
"type": "text",
"size": "col-4"
},
"menu_item_target": {
"title": "admin_menu_item_target",
"type": "select",
"options": {
"self": "_self",
"blank": "_blank",
"parent": "_parent",
"top": "_top"
},
"size": "col-4"
},
"menu_item_order": {
"title": "admin_menu_item_order",
"type": "text",
"size": "col-4"
}
}
}
}
}

View File

@@ -0,0 +1,36 @@
{
"title": "Blog Post",
"default_field": "title",
"sections": {
"main": {
"title": "Main",
"fields": {
"title": {
"title": "admin_title",
"type": "text",
"size": "col-12"
},
"summary": {
"title": "admin_summary",
"type": "editor",
"size": "col-12"
},
"content": {
"title": "admin_content",
"type": "editor",
"size": "col-12"
}
}
},
"seo": {
"title": "Seo",
"fields": {
"description": {
"title": "admin_description",
"type": "textarea",
"size": "col-12"
}
}
}
}
}

57
site/fieldsets/blog.json Normal file
View File

@@ -0,0 +1,57 @@
{
"title": "Blog",
"default_field": "title",
"sections": {
"main": {
"title": "Main",
"fields": {
"title": {
"title": "admin_title",
"type": "text",
"size": "col-12"
}
}
},
"seo": {
"title": "Seo",
"fields": {
"description": {
"title": "admin_description",
"type": "textarea",
"size": "col-12"
}
}
},
"menu": {
"title": "Menu",
"fields": {
"menu_item_title": {
"title": "admin_menu_item_title",
"type": "text",
"size": "col-4"
},
"menu_item_url": {
"title": "admin_menu_item_url",
"type": "text",
"size": "col-4"
},
"menu_item_target": {
"title": "admin_menu_item_target",
"type": "select",
"options": {
"self": "_self",
"blank": "_blank",
"parent": "_parent",
"top": "_top"
},
"size": "col-4"
},
"menu_item_order": {
"title": "admin_menu_item_order",
"type": "text",
"size": "col-4"
}
}
}
}
}

View File

@@ -0,0 +1,77 @@
{
"title": "Default",
"default_field": "title",
"sections": {
"main": {
"title": "Main",
"fields": {
"title": {
"title": "admin_title",
"type": "text",
"size": "col-12"
},
"content": {
"title": "admin_content",
"type": "editor",
"size": "col-12"
},
"template": {
"title": "admin_template",
"type": "template_select",
"size": "col-4"
},
"visibility": {
"title": "admin_visibility",
"type": "visibility_select",
"size": "col-4"
},
"date": {
"title": "admin_date",
"type": "text",
"size": "col-4"
}
}
},
"seo": {
"title": "Seo",
"fields": {
"description": {
"title": "admin_description",
"type": "textarea",
"size": "col-12"
}
}
},
"menu": {
"title": "Menu",
"fields": {
"menu_item_title": {
"title": "admin_menu_item_title",
"type": "text",
"size": "col-4"
},
"menu_item_url": {
"title": "admin_menu_item_url",
"type": "text",
"size": "col-4"
},
"menu_item_target": {
"title": "admin_menu_item_target",
"type": "select",
"options": {
"self": "_self",
"blank": "_blank",
"parent": "_parent",
"top": "_top"
},
"size": "col-4"
},
"menu_item_order": {
"title": "admin_menu_item_order",
"type": "text",
"size": "col-4"
}
}
}
}
}

View File

View File

@@ -1,14 +0,0 @@
title: Default
items:
home:
title: 'Home'
url: 'home'
order: 1
blog:
title: 'Blog'
url: 'blog'
order: 2
about:
title: 'About'
url: 'about'
order: 3

View File

@@ -1,188 +0,0 @@
<?php
namespace Flextype;
/**
*
* Flextype Admin Plugin
*
* @author Romanenko Sergey / Awilum <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.
*/
use Flextype\Component\Arr\Arr;
use Flextype\Component\Number\Number;
use Flextype\Component\I18n\I18n;
use Flextype\Component\Http\Http;
use Flextype\Component\Event\Event;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Session\Session;
use Flextype\Component\Registry\Registry;
use Flextype\Component\Token\Token;
use Flextype\Component\Text\Text;
use Flextype\Component\Notification\Notification;
use Flextype\Component\Form\Form;
use function Flextype\Component\I18n\__;
use Symfony\Component\Yaml\Yaml;
use Gajus\Dindent\Indenter;
//
// If isAdminArea
//
if (Admin::isAdminArea()) {
// Ensure vendor libraries exist
!is_file($autoload = __DIR__ . '/vendor/autoload.php') and exit("Please run: <i>composer install</i>");
// Register The Auto Loader
$loader = require_once $autoload;
//
// Add listner for onCurrentPageBeforeLoaded event
//
Event::addListener('onCurrentEntryBeforeLoaded', function () {
// Add navigation links
NavigationManager::addItem('content', 'entries', '<i class="far fa-newspaper"></i>' . __('admin_menu_content_entries', Registry::get('settings.locale')), Http::getBaseUrl() . '/admin/entries', ['class' => 'nav-link']);
NavigationManager::addItem('extends', 'menus', '<i class="fab fa-elementor"></i>' . __('admin_menu_content_menus', Registry::get('settings.locale')), Http::getBaseUrl() . '/admin/menus', ['class' => 'nav-link']);
NavigationManager::addItem('extends', 'fieldsets', '<i class="fas fa-list"></i>' . __('admin_menu_extends_fieldsets', Registry::get('settings.locale')), Http::getBaseUrl() . '/admin/fieldsets', ['class' => 'nav-link']);
NavigationManager::addItem('extends', 'templates', '<i class="fas fa-layer-group"></i>' . __('admin_menu_extends_templates', Registry::get('settings.locale')), Http::getBaseUrl() . '/admin/templates', ['class' => 'nav-link']);
NavigationManager::addItem('extends', 'snippets', '<i class="far fa-file-code"></i>' . __('admin_menu_extends_snippets', Registry::get('settings.locale')), Http::getBaseUrl() . '/admin/snippets', ['class' => 'nav-link']);
NavigationManager::addItem('extends', 'plugins', '<i class="fas fa-plug"></i>' . __('admin_menu_extends_plugins', Registry::get('settings.locale')), Http::getBaseUrl() . '/admin/plugins', ['class' => 'nav-link']);
NavigationManager::addItem('settings', 'settings', '<i class="fas fa-cog"></i>' . __('admin_menu_system_settings', Registry::get('settings.locale')), Http::getBaseUrl() . '/admin/settings', ['class' => 'nav-link']);
NavigationManager::addItem('settings', 'infomation', '<i class="fas fa-info"></i>' . __('admin_menu_system_information', Registry::get('settings.locale')), Http::getBaseUrl() . '/admin/information', ['class' => 'nav-link']);
if (Registry::get('settings.locale') == 'ru') {
NavigationManager::addItem('help', 'documentation', '<i class="far fa-question-circle"></i>' . __('admin_menu_help_documentation', Registry::get('settings.locale')), 'http://flextype.ru/documentation/basics/getting-help', ['class' => 'nav-link', 'target' => '_blank']);
} else {
NavigationManager::addItem('help', 'documentation', '<i class="far fa-question-circle"></i>' . __('admin_menu_help_documentation', Registry::get('settings.locale')), 'http://flextype.org/documentation/basics/getting-help', ['class' => 'nav-link', 'target' => '_blank']);
}
// Initializes the Notification service.
Notification::init();
// Get Admin Instance
Admin::getInstance();
});
}
class Admin
{
/**
* An instance of the Admin class
*
* @var object
* @access private
*/
private static $instance = null;
/**
* Private clone method to enforce singleton behavior.
*
* @access private
*/
private function __clone()
{
}
/**
* Private wakeup method to enforce singleton behavior.
*
* @access private
*/
private function __wakeup()
{
}
/**
* Private construct method to enforce singleton behavior.
*
* @access private
*/
protected function __construct()
{
Admin::init();
}
/**
* Init Flextype Admin
*
* @access private
*/
private static function init() : void
{
// Set Default Admin locale
I18n::$locale = Registry::get('settings.locale');
if (UsersManager::isLoggedIn()) {
Admin::getAdminArea();
} else {
if (UsersManager::isUsersExists()) {
UsersManager::getAuthPage();
} else {
UsersManager::getRegistrationPage();
}
}
// Event: onBeforeRequestShutdown
Event::dispatch('onBeforeRequestShutdown');
// Shutdown request
Http::requestShutdown();
}
/**
* Flextype Admin Area
*
* @access private
*/
private static function getAdminArea() : void
{
// Event: onAdminArea
Event::dispatch('onAdminArea');
// Route the Uri
Http::getUriSegment(1) == '' and DashboardManager::getDashboardManager();
Http::getUriSegment(1) == 'entries' and EntriesManager::getEntriesManager();
Http::getUriSegment(1) == 'menus' and MenusManager::getMenusManager();
Http::getUriSegment(1) == 'fieldsets' and FieldsetsManager::getFieldsetsManager();
Http::getUriSegment(1) == 'templates' and TemplatesManager::getTemplatesManager();
Http::getUriSegment(1) == 'snippets' and SnippetsManager::getSnippetsManager();
Http::getUriSegment(1) == 'plugins' and PluginsManager::getPluginsManager();
Http::getUriSegment(1) == 'information' and InformationManager::getInformationManager();
Http::getUriSegment(1) == 'settings' and SettingsManager::getSettingsManager();
Http::getUriSegment(1) == 'profile' and UsersManager::getProfileManager();
Http::getUriSegment(1) == 'logout' and UsersManager::logout();
}
/**
* Check is Admin Area
*
* @access public
*/
public static function isAdminArea()
{
return (Http::getUriSegment(0) == 'admin') ? true : false;
}
/**
* Get the Admin instance.
*
* @access public
* @return object
*/
public static function getInstance()
{
if (is_null(Admin::$instance)) {
Admin::$instance = new self;
}
return Admin::$instance;
}
}

View File

@@ -1,10 +0,0 @@
name: Admin
version: 0.0.0
description: "Admin plugin for Flextype"
author:
name: Sergey Romanenko
email: awilum@yandex.ru
url: http://flextype.org
homepage: https://github.com/flextype-plugins/admin
bugs: https://github.com/flextype-plugins/admin/issues
license: MIT

View File

@@ -0,0 +1,25 @@
<?php
namespace Flextype;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
/**
* @property Router $router
*/
class DashboardController extends Controller
{
/**
* Index page
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function index(/** @scrutinizer ignore-unused */ Request $request, Response $response) : Response
{
return $response->withRedirect($this->router->pathFor('admin.entries.index'));
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,192 @@
<?php
namespace Flextype;
use Flextype\Component\Arr\Arr;
use Flextype\Component\Text\Text;
use function Flextype\Component\I18n\__;
use Respect\Validation\Validator as v;
/**
* @property View $view
* @property Fieldsets $fieldsets
* @property Router $router
* @property Slugify $slugify
*/
class FieldsetsController extends Controller
{
public function index($request, $response)
{
return $this->view->render(
$response,
'plugins/admin/views/templates/extends/fieldsets/index.html',
[
'menu_item' => 'fieldsets',
'fieldsets_list' => $this->fieldsets->fetchAll(),
'links' => [
'fieldsets' => [
'link' => $this->router->pathFor('admin.fieldsets.index'),
'title' => __('admin_fieldsets'),
'attributes' => ['class' => 'navbar-item active']
],
],
'buttons' => [
'fieldsets_add' => [
'link' => $this->router->pathFor('admin.fieldsets.add'),
'title' => __('admin_create_new_fieldset'),
'attributes' => ['class' => 'float-right btn']
]
]
]
);
}
public function add($request, $response)
{
return $this->view->render(
$response,
'plugins/admin/views/templates/extends/fieldsets/add.html',
[
'menu_item' => 'fieldsets',
'fieldsets_list' => $this->fieldsets->fetchAll(),
'links' => [
'fieldsets' => [
'link' => $this->router->pathFor('admin.fieldsets.index'),
'title' => __('admin_fieldsets'),
'attributes' => ['class' => 'navbar-item active']
],
],
'buttons' => [
'fieldsets_add' => [
'link' => $this->router->pathFor('admin.fieldsets.add'),
'title' => __('admin_create_new_fieldset'),
'attributes' => ['class' => 'float-right btn']
]
]
]
);
}
public function addProcess($request, $response)
{
$data = $request->getParsedBody();
Arr::delete($data, 'csrf_name');
Arr::delete($data, 'csrf_value');
$id = $this->slugify->slugify($data['id']);
$data = ['title' => $data['title']];
if ($this->fieldsets->create($id, $data)) {
$this->flash->addMessage('success', __('admin_message_fieldset_created'));
} else {
$this->flash->addMessage('error', __('admin_message_fieldset_was_not_created'));
}
return $response->withRedirect($this->router->pathFor('admin.fieldsets.index'));
}
public function edit($request, $response)
{
return $this->view->render(
$response,
'plugins/admin/views/templates/extends/fieldsets/edit.html',
[
'menu_item' => 'fieldsets',
'id' => $request->getQueryParams()['id'],
'data' => JsonParser::encode($this->fieldsets->fetch($request->getQueryParams()['id'])),
'links' => [
'fieldsets' => [
'link' => $this->router->pathFor('admin.fieldsets.edit') . '?id=' . $request->getQueryParams()['id'],
'title' => __('admin_fieldsets'),
'attributes' => ['class' => 'navbar-item active']
],
],
'buttons' => [
'save_entry' => [
'link' => 'javascript:;',
'title' => __('admin_save'),
'attributes' => ['class' => 'js-save-form-submit float-right btn']
],
]
]
);
}
public function editProcess($request, $response)
{
$data = $request->getParsedBody()['data'];
if (v::json()->validate($data)) {
if ($this->fieldsets->update($request->getParsedBody()['id'], JsonParser::decode($data))) {
$this->flash->addMessage('success', __('admin_message_fieldset_saved'));
} else {
$this->flash->addMessage('error', __('admin_message_fieldset_was_not_saved'));
}
return $response->withRedirect($this->router->pathFor('admin.fieldsets.index'));
} else {
$this->flash->addMessage('error', __('admin_message_json_invalid'));
return $response->withRedirect($this->router->pathFor('admin.fieldsets.index'));
}
}
public function rename($request, $response)
{
return $this->view->render(
$response,
'plugins/admin/views/templates/extends/fieldsets/rename.html',
[
'menu_item' => 'fieldsets',
'id' => $request->getQueryParams()['id'],
'links' => [
'fieldsets' => [
'link' => $this->router->pathFor('admin.fieldsets.index'),
'title' => __('admin_fieldsets'),
'attributes' => ['class' => 'navbar-item active']
],
'fieldsets_rename' => [
'link' => $this->router->pathFor('admin.fieldsets.rename') . '?id=' . $request->getQueryParams()['id'],
'title' => __('admin_rename'),
'attributes' => ['class' => 'navbar-item active']
],
],
]
);
}
public function renameProcess($request, $response)
{
if ($this->fieldsets->rename($request->getParsedBody()['fieldset-id-current'], $request->getParsedBody()['id'])) {
$this->flash->addMessage('success', __('admin_message_fieldset_renamed'));
} else {
$this->flash->addMessage('error', __('admin_message_fieldset_was_not_renamed'));
}
return $response->withRedirect($this->router->pathFor('admin.fieldsets.index'));
}
public function deleteProcess($request, $response)
{
if ($this->fieldsets->delete($request->getParsedBody()['fieldset-id'])) {
$this->flash->addMessage('success', __('admin_message_fieldset_deleted'));
} else {
$this->flash->addMessage('error', __('admin_message_fieldset_was_not_deleted'));
}
return $response->withRedirect($this->router->pathFor('admin.fieldsets.index'));
}
public function duplicateProcess($request, $response)
{
if ($this->fieldsets->copy($request->getParsedBody()['fieldset-id'], $request->getParsedBody()['fieldset-id'] . '-duplicate-' . date("Ymd_His"))) {
$this->flash->addMessage('success', __('admin_message_fieldset_duplicated'));
} else {
$this->flash->addMessage('error', __('admin_message_fieldset_was_not_duplicated'));
}
return $response->withRedirect($this->router->pathFor('admin.fieldsets.index'));
}
}

View File

@@ -0,0 +1,54 @@
<?php
namespace Flextype;
use function Flextype\Component\I18n\__;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
/**
* @property View $view
* @property Router $router
*/
class InformationController extends Controller
{
/**
* Index page
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function index(/** @scrutinizer ignore-unused */ Request $request, Response $response) : Response
{
if (function_exists('apache_get_modules')) {
if (!in_array('mod_rewrite', apache_get_modules())) {
$apache_mod_rewrite_installed = false;
} else {
$apache_mod_rewrite_installed = true;
}
} else {
$apache_mod_rewrite_installed = true;
}
return $this->view->render(
$response,
'plugins/admin/views/templates/system/information/index.html',
[
'menu_item' => 'infomation',
'php_uname' => php_uname(),
'webserver' => isset($_SERVER['SERVER_SOFTWARE']) ? $_SERVER['SERVER_SOFTWARE'] : @getenv('SERVER_SOFTWARE'),
'php_sapi_name' => php_sapi_name(),
'apache_mod_rewrite_installed' => $apache_mod_rewrite_installed,
'links' => [
'information' => [
'link' => $this->router->pathFor('admin.information.index'),
'title' => __('admin_information'),
'attributes' => ['class' => 'navbar-item active']
],
]
]
);
}
}

View File

@@ -0,0 +1,73 @@
<?php
namespace Flextype;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Date\Date;
use Flextype\Component\Arr\Arr;
use function Flextype\Component\I18n\__;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
/**
* @property View $view
* @property Router $router
* @property Cache $cache
* @property Registry $registry
*/
class PluginsController extends Controller
{
/**
* Index page
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function index(/** @scrutinizer ignore-unused */ Request $request, Response $response) : Response
{
return $this->view->render(
$response,
'plugins/admin/views/templates/extends/plugins/index.html',
[
'plugins_list' => $this->registry->get('plugins'),
'menu_item' => 'plugins',
'links' => [
'plugins' => [
'link' => $this->router->pathFor('admin.plugins.index'),
'title' => __('admin_plugins'),
'attributes' => ['class' => 'navbar-item active']
],
],
'buttons' => [
'plugins_get_more' => [
'link' => 'https://github.com/flextype/plugins',
'title' => __('admin_get_more_plugins'),
'attributes' => ['class' => 'float-right btn', 'target' => '_blank']
],
]
]
);
}
/**
* Сhange plugin status process
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function pluginStatusProcess(Request $request, Response $response) : Response
{
$data = $request->getParsedBody();
$plugin_settings = JsonParser::decode(Filesystem::read(PATH['plugins'] . '/' . $data['plugin-key'] . '/' . 'settings.json'));
Arr::set($plugin_settings, 'enabled', ($data['plugin-status'] == 'true' ? true : false));
Filesystem::write(PATH['plugins'] . '/' . $data['plugin-key'] . '/' . 'settings.json', JsonParser::encode($plugin_settings));
$this->cache->clear();
return $response->withRedirect($this->router->pathFor('admin.plugins.index'));
}
}

View File

@@ -0,0 +1,144 @@
<?php
namespace Flextype;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Date\Date;
use Flextype\Component\Arr\Arr;
use function Flextype\Component\I18n\__;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
/**
* @property View $view
* @property Router $router
* @property Cache $cache
*/
class SettingsController extends Controller
{
/**
* Index page
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function index(/** @scrutinizer ignore-unused */ Request $request, Response $response) : Response
{
$entries = [];
foreach ($this->entries->fetchAll('', 'date', 'DESC') as $entry) {
$entries[$entry['slug']] = $entry['title'];
}
$themes = [];
foreach (Filesystem::listContents(PATH['themes']) as $theme) {
if ($theme['type'] == 'dir' && Filesystem::has($theme['path'] . '/' . 'theme.json')) {
$themes[$theme['dirname']] = $theme['dirname'];
}
}
$available_locales = Filesystem::listContents(PATH['plugins'] . '/admin/lang/');
$system_locales = $this->plugins->getLocales();
$locales = [];
foreach ($available_locales as $locale) {
if ($locale['type'] == 'file' && $locale['extension'] == 'json') {
$locales[$locale['basename']] = $system_locales[$locale['basename']]['nativeName'];
}
}
$cache_driver = ['auto' => 'Auto Detect',
'file' => 'File',
'apcu' => 'APCu',
'wincache' => 'WinCache',
'memcached' => 'Memcached',
'redis' => 'Redis',
'sqlite3' => 'SQLite3',
'zend' => 'Zend',
'array' => 'Array'];
return $this->view->render(
$response,
'plugins/admin/views/templates/system/settings/index.html',
[
'timezones' => Date::timezones(),
'settings' => $this->registry->get('settings'),
'cache_driver' => $cache_driver,
'locales' => $locales,
'entries' => $entries,
'themes' => $themes,
'menu_item' => 'settings',
'links' => [
'settings' => [
'link' => $this->router->pathFor('admin.settings.index'),
'title' => __('admin_settings'),
'attributes' => ['class' => 'navbar-item active']
]
],
'buttons' => [
'save' => [
'link' => 'javascript:;',
'title' => __('admin_save'),
'attributes' => ['class' => 'js-save-form-submit float-right btn']
],
'settings_clear_cache' => [
'type' => 'action',
'id' => 'clear-cache',
'link' => $this->router->pathFor('admin.settings.clear-cache'),
'title' => __('admin_clear_cache'),
'attributes' => ['class' => 'float-right btn']
]
]
]
);
}
/**
* Update settings process
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function updateSettingsProcess(Request $request, Response $response) : Response
{
$data = $request->getParsedBody();
Arr::delete($data, 'csrf_name');
Arr::delete($data, 'csrf_value');
Arr::delete($data, 'action');
Arr::set($data, 'errors.display', ($data['errors']['display'] == '1' ? true : false));
Arr::set($data, 'cache.enabled', ($data['cache']['enabled'] == '1' ? true : false));
Arr::set($data, 'cache.lifetime', (int) $data['cache']['lifetime']);
Arr::set($data, 'entries.media.upload_images_quality', (int) $data['entries']['media']['upload_images_quality']);
Arr::set($data, 'entries.media.upload_images_width', (int) $data['entries']['media']['upload_images_width']);
Arr::set($data, 'entries.media.upload_images_height', (int) $data['entries']['media']['upload_images_height']);
if (Filesystem::write(PATH['config']['site'] . '/settings.json', JsonParser::encode(array_merge($this->registry->get('settings'), $data)))) {
$this->flash->addMessage('success', __('admin_message_settings_saved'));
} else {
$this->flash->addMessage('error', __('admin_message_settings_was_not_saved'));
}
return $response->withRedirect($this->router->pathFor('admin.settings.index'));
}
/**
* Clear cache process
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function clearCacheProcess(/** @scrutinizer ignore-unused */ Request $request, Response $response) : Response
{
$this->cache->clear();
Filesystem::has(PATH['cache'] . '/twig') and Filesystem::deleteDir(PATH['cache'] . '/twig');
$this->flash->addMessage('success', __('admin_message_cache_files_deleted'));
return $response->withRedirect($this->router->pathFor('admin.settings.index'));
}
}

View File

@@ -0,0 +1,254 @@
<?php
namespace Flextype;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Text\Text;
use function Flextype\Component\I18n\__;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
/**
* @property View $view
* @property Router $router
* @property Snippets $snippets
* @property Slugify $slugify
*/
class SnippetsController extends Controller
{
/**
* Index page
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function index(/** @scrutinizer ignore-unused */ Request $request, Response $response) : Response
{
return $this->view->render(
$response,
'plugins/admin/views/templates/extends/snippets/index.html',
[
'menu_item' => 'snippets',
'snippets_list' => $this->snippets->fetchAll(),
'links' => [
'snippets' => [
'link' => $this->router->pathFor('admin.snippets.index'),
'title' => __('admin_snippets'),
'attributes' => ['class' => 'navbar-item active']
],
],
'buttons' => [
'snippets_create' => [
'link' => $this->router->pathFor('admin.snippets.add'),
'title' => __('admin_create_new_snippet'),
'attributes' => ['class' => 'float-right btn']
],
]
]
);
}
/**
* Add snippet
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function add(/** @scrutinizer ignore-unused */ Request $request, Response $response) : Response
{
return $this->view->render(
$response,
'plugins/admin/views/templates/extends/snippets/add.html',
[
'menu_item' => 'snippets',
'links' => [
'snippets' => [
'link' => $this->router->pathFor('admin.snippets.index'),
'title' => __('admin_snippets'),
'attributes' => ['class' => 'navbar-item active']
],
]
]
);
}
/**
* Add snippet process
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function addProcess(Request $request, Response $response) : Response
{
$id = $this->slugify->slugify($request->getParsedBody()['id']);
if ($this->snippets->create($id, "")) {
$this->flash->addMessage('success', __('admin_message_snippet_created'));
} else {
$this->flash->addMessage('error', __('admin_message_snippet_was_not_created'));
}
return $response->withRedirect($this->router->pathFor('admin.snippets.index'));
}
/**
* Edit snippet
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function edit(Request $request, Response $response) : Response
{
$id = $request->getQueryParams()['id'];
return $this->view->render(
$response,
'plugins/admin/views/templates/extends/snippets/edit.html',
[
'menu_item' => 'snippets',
'id' => $id,
'data' => $this->snippets->fetch($id),
'links' => [
'snippets' => [
'link' => $this->router->pathFor('admin.snippets.index'),
'title' => __('admin_snippets'),
'attributes' => ['class' => 'navbar-item active']
],
],
'buttons' => [
'save_snippet' => [
'link' => 'javascript:;',
'title' => __('admin_save'),
'attributes' => ['class' => 'js-save-form-submit float-right btn']
]
]
]
);
}
/**
* Edit snippet process
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function editProcess(Request $request, Response $response) : Response
{
$id = $request->getParsedBody()['id'];
$data = $request->getParsedBody()['data'];
if ($this->snippets->update($id, $data)) {
$this->flash->addMessage('success', __('admin_message_snippet_saved'));
} else {
$this->flash->addMessage('error', __('admin_message_snippet_was_not_saved'));
}
return $response->withRedirect($this->router->pathFor('admin.snippets.index'));
}
/**
* Rename snippet
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function rename(Request $request, Response $response) : Response
{
return $this->view->render(
$response,
'plugins/admin/views/templates/extends/snippets/rename.html',
[
'menu_item' => 'snippets',
'id_current' => $request->getQueryParams()['id'],
'links' => [
'templates' => [
'link' => $this->router->pathFor('admin.snippets.index'),
'title' => __('admin_templates'),
'attributes' => ['class' => 'navbar-item active']
],
]
]
);
}
/**
* Rename snippet process
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function renameProcess(Request $request, Response $response) : Response
{
$id = $this->slugify->slugify($request->getParsedBody()['id']);
$id_current = $request->getParsedBody()['id_current'];
if ($this->snippets->rename(
$id_current,
$id
)
) {
$this->flash->addMessage('success', __('admin_message_snippet_renamed'));
} else {
$this->flash->addMessage('error', __('admin_message_snippet_was_not_renamed'));
}
return $response->withRedirect($this->router->pathFor('admin.snippets.index'));
}
/**
* Delete snippet process
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function deleteProcess(Request $request, Response $response) : Response
{
$id = $request->getParsedBody()['snippet-id'];
if ($this->snippets->delete($id)) {
$this->flash->addMessage('success', __('admin_message_snippet_deleted'));
} else {
$this->flash->addMessage('error', __('admin_message_snippet_was_not_deleted'));
}
return $response->withRedirect($this->router->pathFor('admin.snippets.index'));
}
/**
* Duplicate snippet process
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function duplicateProcess(Request $request, Response $response) : Response
{
$id = $request->getParsedBody()['snippet-id'];
if ($this->snippets->copy($id, $id . '-duplicate-' . date("Ymd_His"))) {
$this->flash->addMessage('success', __('admin_message_snippet_duplicated'));
} else {
$this->flash->addMessage('error', __('admin_message_snippet_was_not_duplicated'));
}
return $response->withRedirect($this->router->pathFor('admin.snippets.index'));
}
}

View File

@@ -0,0 +1,287 @@
<?php
namespace Flextype;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Text\Text;
use function Flextype\Component\I18n\__;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
/**
* @property View $view
* @property Router $router
* @property Cache $cache
* @property Themes $themes
* @property Slugify $slugify
*/
class TemplatesController extends Controller
{
/**
* Index page
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function index(/** @scrutinizer ignore-unused */ Request $request, Response $response) : Response
{
return $this->view->render(
$response,
'plugins/admin/views/templates/extends/templates/index.html',
[
'menu_item' => 'templates',
'templates_list' => $this->themes->getTemplates(),
'partials_list' => $this->themes->getPartials(),
'links' => [
'templates' => [
'link' => $this->router->pathFor('admin.templates.index'),
'title' => __('admin_templates'),
'attributes' => ['class' => 'navbar-item active']
],
],
'buttons' => [
'templates_create' => [
'link' => $this->router->pathFor('admin.templates.add'),
'title' => __('admin_create_new_template'),
'attributes' => ['class' => 'float-right btn']
],
]
]
);
}
/**
* Add template
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function add(/** @scrutinizer ignore-unused */ Request $request, Response $response) : Response
{
return $this->view->render(
$response,
'plugins/admin/views/templates/extends/templates/add.html',
[
'menu_item' => 'templates',
'links' => [
'templates' => [
'link' => $this->router->pathFor('admin.templates.index'),
'title' => __('admin_templates'),
'attributes' => ['class' => 'navbar-item active']
],
]
]
);
}
/**
* Add template process
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function addProcess(Request $request, Response $response) : Response
{
$type = $request->getParsedBody()['type'];
$id = $this->slugify->slugify($request->getParsedBody()['id']) . '.html';
$file = PATH['themes'] . '/' . $this->registry->get('settings.theme') . '/' . $this->_type_location($type) . $id;
if (!Filesystem::has($file)) {
if (Filesystem::write(
$file,
""
)) {
$this->flash->addMessage('success', __('admin_message_'.$type.'_created'));
} else {
$this->flash->addMessage('error', __('admin_message_'.$type.'_was_not_created'));
}
} else {
$this->flash->addMessage('error', __('admin_message_'.$type.'_was_not_created'));
}
return $response->withRedirect($this->router->pathFor('admin.templates.index'));
}
/**
* Edit template
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function edit(Request $request, Response $response) : Response
{
$type = $request->getQueryParams()['type'];
return $this->view->render(
$response,
'plugins/admin/views/templates/extends/templates/edit.html',
[
'menu_item' => 'templates',
'id' => $request->getQueryParams()['id'],
'data' => Filesystem::read(PATH['themes'] . '/' . $this->registry->get('settings.theme') . '/' . $this->_type_location($type) . $request->getQueryParams()['id'] . '.html'),
'type' => (($request->getQueryParams()['type'] && $request->getQueryParams()['type'] == 'partial') ? 'partial' : 'template'),
'links' => [
'templates' => [
'link' => $this->router->pathFor('admin.templates.index'),
'title' => __('admin_templates'),
'attributes' => ['class' => 'navbar-item active']
],
],
'buttons' => [
'save_template' => [
'link' => 'javascript:;',
'title' => __('admin_save'),
'attributes' => ['class' => 'js-save-form-submit float-right btn']
]
]
]
);
}
/**
* Edit template process
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function editProcess(Request $request, Response $response) : Response
{
$type = $request->getParsedBody()['type'];
if (Filesystem::write(PATH['themes'] . '/' . $this->registry->get('settings.theme') . '/' . $this->_type_location($type) . $request->getParsedBody()['id'] . '.html', $request->getParsedBody()['data'])) {
$this->flash->addMessage('success', __('admin_message_' . $type . '_saved'));
} else {
$this->flash->addMessage('error', __('admin_message_' . $type . '_was_not_saved'));
}
return $response->withRedirect($this->router->pathFor('admin.templates.index'));
}
/**
* Rename template
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function rename(Request $request, Response $response) : Response
{
return $this->view->render(
$response,
'plugins/admin/views/templates/extends/templates/rename.html',
[
'menu_item' => 'templates',
'types' => ['partial' => __('admin_partial'), 'template' => __('admin_template')],
'id_current' => $request->getQueryParams()['id'],
'type_current' => (($request->getQueryParams()['type'] && $request->getQueryParams()['type'] == 'partial') ? 'partial' : 'template'),
'links' => [
'templates' => [
'link' => $this->router->pathFor('admin.templates.index'),
'title' => __('admin_templates'),
'attributes' => ['class' => 'navbar-item active']
],
]
]
);
}
/**
* Rename template process
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function renameProcess(Request $request, Response $response) : Response
{
$type = $request->getParsedBody()['type_current'];
if (!Filesystem::has(PATH['themes'] . '/' . $this->registry->get('settings.theme') . '/' . $this->_type_location($type) . $request->getParsedBody()['id'] . '.html')) {
if (Filesystem::rename(
PATH['themes'] . '/' . $this->registry->get('settings.theme') . '/' . $this->_type_location($type) . $request->getParsedBody()['id_current'] . '.html',
PATH['themes'] . '/' . $this->registry->get('settings.theme') . '/' . $this->_type_location($type) . $request->getParsedBody()['id'] . '.html'
)
) {
$this->flash->addMessage('success', __('admin_message_'.$type.'_renamed'));
} else {
$this->flash->addMessage('error', __('admin_message_'.$type.'_was_not_renamed'));
}
} else {
$this->flash->addMessage('error', __('admin_message_'.$type.'_was_not_renamed'));
}
return $response->withRedirect($this->router->pathFor('admin.templates.index'));
}
/**
* Delete template process
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function deleteProcess(Request $request, Response $response) : Response
{
$type = $request->getParsedBody()['type'];
$file_path = PATH['themes'] . '/' . $this->registry->get('settings.theme') . '/' . $this->_type_location($type) . $request->getParsedBody()[$type . '-id'] . '.html';
if (Filesystem::delete($file_path)) {
$this->flash->addMessage('success', __('admin_message_' . $type . '_deleted'));
} else {
$this->flash->addMessage('error', __('admin_message_' . $type . '_was_not_deleted'));
}
return $response->withRedirect($this->router->pathFor('admin.templates.index'));
}
/**
* Duplicate template process
*
* @param Request $request PSR7 request
* @param Response $response PSR7 response
*
* @return Response
*/
public function duplicateProcess(Request $request, Response $response) : Response
{
$type = $request->getParsedBody()['type'];
$file_path = PATH['themes'] . '/' . $this->registry->get('settings.theme') . '/' . $this->_type_location($type) . $request->getParsedBody()[$type . '-id'] . '.html';
$file_path_new = PATH['themes'] . '/' . $this->registry->get('settings.theme') . '/' . $this->_type_location($type) . $request->getParsedBody()[$type . '-id'] . '-duplicate-' . date("Ymd_His") . '.html';
if (Filesystem::copy($file_path, $file_path_new)) {
$this->flash->addMessage('success', __('admin_message_' . $type . '_duplicated'));
} else {
$this->flash->addMessage('error', __('admin_message_' . $type . '_was_not_duplicated'));
}
return $response->withRedirect($this->router->pathFor('admin.templates.index'));
}
private function _type_location($type)
{
if ($type == 'partial') {
$_type = '/templates/partials/';
} else {
$_type = '/templates/';
}
return $_type;
}
}

View File

@@ -0,0 +1,128 @@
<?php
namespace Flextype;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Session\Session;
use Flextype\Component\Text\Text;
use function Flextype\Component\I18n\__;
/**
* @property View $view
* @property Router $router
* @property Slugify $slugify
*/
class UsersController extends Controller
{
public function profile($request, $response)
{
return $this->container->get('view')->render(
$response,
'plugins/admin/views/templates/users/profile.html'
);
}
public function login($request, $response)
{
$users = $this->getUsers();
if ((Session::exists('role') && Session::get('role') == 'admin')) {
return $response->withRedirect($this->router->pathFor('admin.entries.index'));
} else {
if ($users && count($users) > 0) {
return $this->container->get('view')->render(
$response,
'plugins/admin/views/templates/users/login.html'
);
} else {
return $response->withRedirect($this->router->pathFor('admin.users.registration'));
}
}
}
public function loginProcess($request, $response)
{
$data = $request->getParsedBody();
if (Filesystem::has($_user_file = PATH['site'] . '/accounts/' . $data['username'] . '.json')) {
$user_file = JsonParser::decode(Filesystem::read($_user_file));
if (password_verify(trim($data['password']), $user_file['hashed_password'])) {
Session::set('username', $user_file['username']);
Session::set('role', $user_file['role']);
return $response->withRedirect($this->router->pathFor('admin.entries.index'));
} else {
$this->flash->addMessage('error', __('admin_message_wrong_username_password'));
return $response->withRedirect($this->router->pathFor('admin.users.login'));
}
} else {
$this->flash->addMessage('error', __('admin_message_wrong_username_password'));
return $response->withRedirect($this->router->pathFor('admin.users.login'));
}
}
public function registration($request, $response)
{
if ((Session::exists('role') && Session::get('role') == 'admin')) {
return $response->withRedirect($this->router->pathFor('admin.entries.index'));
} else {
return $this->view->render(
$response,
'plugins/admin/views/templates/users/registration.html'
);
}
}
/**
* registrationProcess
*/
public function registrationProcess($request, $response)
{
// Get POST data
$data = $request->getParsedBody();
if (!Filesystem::has($_user_file = PATH['site'] . '/accounts/' . $this->slugify->slugify($data['username']) . '.json')) {
Filesystem::createDir(PATH['site'] . '/accounts/');
if (Filesystem::write(
PATH['site'] . '/accounts/' . $data['username'] . '.json',
JsonParser::encode(['username' => $this->slugify->slugify($data['username']),
'hashed_password' => password_hash($data['password'], PASSWORD_BCRYPT),
'email' => $data['email'],
'role' => 'admin',
'state' => 'enabled'])
)) {
return $response->withRedirect($this->router->pathFor('admin.users.login'));
} else {
return $response->withRedirect($this->router->pathFor('admin.users.registration'));
}
} else {
return $response->withRedirect($this->router->pathFor('admin.users.registration'));
}
}
/**
* logoutProcess
*/
public function logoutProcess($request, $response)
{
Session::destroy();
return $response->withRedirect($this->router->pathFor('admin.users.login'));
}
public function getUsers()
{
// Get Users Profiles
$users = Filesystem::listContents(PATH['site'] . '/accounts/');
// Get Plugins List
$_users_list = Filesystem::listContents(PATH['plugins']);
$users_list = [];
foreach($_users_list as $user) {
if ($user['type'] == 'dir') {
$users_list[] = $user;
}
}
return $users;
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace Flextype;
use Flextype\Component\Session\Session;
class AuthMiddleware extends Middleware
{
public function __invoke($request, $response, $next)
{
if (Session::exists('role') && Session::get('role') == 'admin') {
$response = $next($request, $response);
} else {
$response = $response->withRedirect($this->router->pathFor('admin.users.login'));
}
return $response;
}
}

View File

@@ -1,5 +1,5 @@
// Admin Theme main SCSS
// (c) Sergey Romanenko <https://github.com/Awilum>
// (c) Sergey Romanenko <http://romanenko.digital>
// Generic
// Low-specificity, far-reaching rulesets

View File

@@ -181,3 +181,19 @@
margin-right: 10px;
}
}
.nav-pills {
margin-bottom: 20px;
}
.nav-pills .nav-link {
border-radius: 0;
color: black;
}
.nav-pills .nav-link.active,
.nav-pills .show > .nav-link {
background: none;
border-bottom: 1px solid #ccc;
color: black;
}

View File

@@ -38,6 +38,10 @@
border: 1px solid #000;
}
.input-group-append > .btn {
padding: 6.5px 16px;
}
.dropdown-item {
color: $btn-text-color;

View File

@@ -0,0 +1,85 @@
<?php
namespace Flextype;
/**
*
* Flextype Admin Plugin
*
* @author Romanenko Sergey / Awilum <hello@romanenko.digital>
* @link http://romanenko.digital
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Flextype\Component\Arr\Arr;
use Flextype\Component\I18n\I18n;
use function Flextype\Component\I18n\__;
// Get URI
$uri = explode('/', \Slim\Http\Uri::createFromEnvironment(new \Slim\Http\Environment($_SERVER))->getPath());
// Set base admin route
$admin_route = 'admin';
// Ensure vendor libraries exist
!is_file($autoload = __DIR__ . '/vendor/autoload.php') and exit("Please run: <i>composer install</i>");
// Register The Auto Loader
$loader = require_once $autoload;
// Include routes
include_once 'routes/web.php';
// Set Default Admin locale
I18n::$locale = $flextype->registry->get('settings.locale');
// Add Admin Navigation
$flextype->registry->set('admin_navigation.content.entries', ['title' => '<i class="far fa-newspaper"></i>' . __('admin_entries'), 'link' => $flextype->router->pathFor('admin.entries.index'), 'attributes' => ['class' => 'nav-link']]);
$flextype->registry->set('admin_navigation.extends.fieldsets', ['title' => '<i class="fas fa-list"></i>' . __('admin_fieldsets'), 'link' => $flextype->router->pathFor('admin.fieldsets.index'), 'attributes' => ['class' => 'nav-link']]);
$flextype->registry->set('admin_navigation.extends.templates', ['title' => '<i class="fas fa-layer-group"></i>' . __('admin_templates'), 'link' => $flextype->router->pathFor('admin.templates.index'), 'attributes' => ['class' => 'nav-link']]);
$flextype->registry->set('admin_navigation.extends.snippets', ['title' => '<i class="far fa-file-code"></i>' . __('admin_snippets'), 'link' => $flextype->router->pathFor('admin.snippets.index'), 'attributes' => ['class' => 'nav-link']]);
$flextype->registry->set('admin_navigation.extends.plugins', ['title' => '<i class="fas fa-plug"></i>' . __('admin_plugins'), 'link' => $flextype->router->pathFor('admin.plugins.index'), 'attributes' => ['class' => 'nav-link']]);
$flextype->registry->set('admin_navigation.settings.settings', ['title' => '<i class="fas fa-cog"></i>' . __('admin_settings'), 'link' => $flextype->router->pathFor('admin.settings.index'), 'attributes' => ['class' => 'nav-link']]);
$flextype->registry->set('admin_navigation.settings.infomation', ['title' => '<i class="fas fa-info"></i>' . __('admin_information'), 'link' => $flextype->router->pathFor('admin.information.index'), 'attributes' => ['class' => 'nav-link']]);
$flextype->registry->set('admin_navigation.help.docs', ['title' => '<i class="far fa-question-circle"></i>' . __('admin_documentation'), 'link' => 'http://flextype.org/en/documentation', 'attributes' => ['class' => 'nav-link', 'target' => '_blank']]);
// Add Global Vars Admin Twig Extension
$flextype->view->addExtension(new GlobalVarsAdminTwigExtension($flextype));
$flextype['DashboardController'] = function ($container) {
return new DashboardController($container);
};
$flextype['SettingsController'] = function ($container) {
return new SettingsController($container);
};
$flextype['InformationController'] = function ($container) {
return new InformationController($container);
};
$flextype['PluginsController'] = function ($container) {
return new PluginsController($container);
};
$flextype['EntriesController'] = function ($container) {
return new EntriesController($container);
};
$flextype['FieldsetsController'] = function ($container) {
return new FieldsetsController($container);
};
$flextype['SnippetsController'] = function ($container) {
return new SnippetsController($container);
};
$flextype['TemplatesController'] = function ($container) {
return new TemplatesController($container);
};
$flextype['UsersController'] = function ($container) {
return new UsersController($container);
};

View File

@@ -1,13 +0,0 @@
<?php
namespace Flextype;
use Flextype\Component\Http\Http;
class DashboardManager
{
public static function getDashboardManager()
{
Http::redirect(Http::getBaseUrl().'/admin/entries');
}
}

View File

@@ -1,659 +0,0 @@
<?php
namespace Flextype;
use Flextype\Component\Arr\Arr;
use Flextype\Component\Number\Number;
use Flextype\Component\I18n\I18n;
use Flextype\Component\Http\Http;
use Flextype\Component\Event\Event;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Session\Session;
use Flextype\Component\Registry\Registry;
use Flextype\Component\Token\Token;
use Flextype\Component\Text\Text;
use Flextype\Component\Form\Form;
use Flextype\Component\Notification\Notification;
use function Flextype\Component\I18n\__;
use Gajus\Dindent\Indenter;
use Intervention\Image\ImageManagerStatic as Image;
class EntriesManager
{
public static function getEntriesManager()
{
Registry::set('sidebar_menu_item', 'entries');
if (Http::get('entry') && Http::get('entry') != '') {
$query = Http::get('entry');
} else {
$query = '';
}
switch (Http::getUriSegment(2)) {
case 'add':
$create_entry = Http::post('create_entry');
if (isset($create_entry)) {
if (Token::check((Http::post('token')))) {
$file = PATH['entries'] . '/' . Http::post('parent_entry') . '/' . Text::safeString(Http::post('slug'), '-', true) . '/entry.html';
if (!Filesystem::fileExists($file)) {
// Get fieldset
$fieldset = YamlParser::decode(Filesystem::getFileContent(PATH['themes'] . '/' . Registry::get('settings.theme') . '/fieldsets/' . Http::post('fieldset') . '.yaml'));
// We need to check if template for current fieldset is exists
// if template is not exist then default template will be used!
$template_path = PATH['themes'] . '/' . Registry::get('settings.theme') . '/views/templates/' . Http::post('fieldset') . '.php';
if (Filesystem::fileExists($template_path)) {
$template = Http::post('fieldset');
} else {
$template = 'default';
}
// Init frontmatter
$frontmatter = [];
$_frontmatter = [];
// Define frontmatter values based on POST data
$_frontmatter['title'] = Http::post('title');
$_frontmatter['template'] = $template;
$_frontmatter['fieldset'] = Http::post('fieldset');
$_frontmatter['date'] = date(Registry::get('settings.date_format'), time());
// Define frontmatter values based on fieldset
foreach ($fieldset['fields'] as $key => $field) {
if (isset($_frontmatter[$key])) {
$_value = $_frontmatter[$key];
} elseif(isset($field['value'])) {
$_value = $field['value'];
} else {
$_value = '';
}
$frontmatter[$key] = $_value;
}
// Delete content field from frontmatter
Arr::delete($frontmatter, 'content');
// Create a entry!
if (Filesystem::setFileContent(
$file,
'---'."\n".
YamlParser::encode(array_replace_recursive($frontmatter, $_frontmatter)).
'---'."\n"
)) {
Notification::set('success', __('admin_message_entry_created'));
Http::redirect(Http::getBaseUrl().'/admin/entries/?entry='.Http::post('parent_entry'));
}
}
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
Themes::view('admin/views/templates/content/entries/add')
->assign('fieldsets', Themes::getFieldsets())
->assign('entries_list', Entries::getEntries('', 'slug'))
->display();
break;
case 'delete':
if (Http::get('entry') != '') {
if (Token::check((Http::get('token')))) {
Filesystem::deleteDir(PATH['entries'] . '/' . Http::get('entry'));
Notification::set('success', __('admin_message_entry_deleted'));
Http::redirect(Http::getBaseUrl() . '/admin/entries/?entry=' . Http::get('entry_current'));
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
break;
case 'duplicate':
if (Http::get('entry') != '') {
if (Token::check((Http::get('token')))) {
Filesystem::recursiveCopy(PATH['entries'] . '/' . Http::get('entry'),
PATH['entries'] . '/' . Http::get('entry') . '-duplicate-' . date("Ymd_His"));
Notification::set('success', __('admin_message_entry_duplicated'));
Http::redirect(Http::getBaseUrl().'/admin/entries/?entry='.implode('/', array_slice(explode("/", Http::get('entry')), 0, -1)));
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
break;
case 'rename':
$entry = Entries::processEntry(PATH['entries'] . '/' . Http::get('entry') . '/entry.html', false, true);
$rename_entry = Http::post('rename_entry');
if (isset($rename_entry)) {
if (Token::check((Http::post('token')))) {
if (!Filesystem::dirExists(PATH['entries'] . '/' . Http::post('name'))) {
if (rename(
PATH['entries'] . '/' . Http::post('entry_path_current'),
PATH['entries'] . '/' . Http::post('entry_parent') . '/' . Text::safeString(Http::post('name'), '-', true)
)) {
Notification::set('success', __('admin_message_entry_renamed'));
Http::redirect(Http::getBaseUrl().'/admin/entries/?entry='.Http::post('entry_parent'));
}
}
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
Themes::view('admin/views/templates/content/entries/rename')
->assign('name_current', Arr::last(explode("/", Http::get('entry'))))
->assign('entry_path_current', Http::get('entry'))
->assign('entry_parent', implode('/', array_slice(explode("/", Http::get('entry')), 0, -1)))
->assign('entry', $entry)
->display();
break;
case 'type':
$type_entry = Http::post('type_entry');
if (isset($type_entry)) {
if (Token::check((Http::post('token')))) {
$entry = Entries::processEntry(PATH['entries'] . '/' . Http::get('entry') . '/entry.html', false, true);
$content = $entry['content'];
Arr::delete($entry, 'content');
Arr::delete($entry, 'url');
Arr::delete($entry, 'slug');
Arr::delete($entry, 'base_url');
$frontmatter = $_POST;
Arr::delete($frontmatter, 'token');
Arr::delete($frontmatter, 'type_entry');
Arr::delete($frontmatter, 'entry');
$frontmatter = YamlParser::encode(array_merge($entry, $frontmatter));
if (Filesystem::setFileContent(
PATH['entries'] . '/' . Http::post('entry') . '/entry.html',
'---'."\n".
$frontmatter."\n".
'---'."\n".
$content
)) {
Notification::set('success', __('admin_message_entry_changes_saved'));
Http::redirect(Http::getBaseUrl() . '/admin/entries?entry='.implode('/', array_slice(explode("/", Http::get('entry')), 0, -1)));
}
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
$entry = Entries::processEntry(PATH['entries'] . '/' . Http::get('entry') . '/entry.html', false, true);
Themes::view('admin/views/templates/content/entries/type')
->assign('fieldset', $entry['fieldset'])
->assign('fieldsets', Themes::getFieldsets())
->display();
break;
case 'move':
$entry = Entries::processEntry(PATH['entries'] . '/' . Http::get('entry') . '/entry.html', false, true);
$move_entry = Http::post('move_entry');
if (isset($move_entry)) {
if (Token::check((Http::post('token')))) {
if (!Filesystem::dirExists(realpath(PATH['entries'] . '/' . Http::post('parent_entry') . '/' . Http::post('name_current')))) {
if (rename(
PATH['entries'] . '/' . Http::post('entry_path_current'),
PATH['entries'] . '/' . Http::post('parent_entry') . '/' . Text::safeString(Http::post('name_current'), '-', true)
)) {
Notification::set('success', __('admin_message_entry_moved'));
Http::redirect(Http::getBaseUrl().'/admin/entries/?entry='.Http::post('parent_entry'));
}
}
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
$_entries_list = Entries::getEntries('', 'slug');
$entries_list['/'] = '/';
foreach ($_entries_list as $_entry) {
if ($_entry['slug'] != '') {
$entries_list[$_entry['slug']] = $_entry['slug'];
} else {
$entries_list[Registry::get('settings.entries.main')] = Registry::get('settings.entries.main');
}
}
Themes::view('admin/views/templates/content/entries/move')
->assign('entry_path_current', Http::get('entry'))
->assign('entries_list', $entries_list)
->assign('name_current', Arr::last(explode("/", Http::get('entry'))))
->assign('entry_parent', implode('/', array_slice(explode("/", Http::get('entry')), 0, -1)))
->assign('entry', $entry)
->display();
break;
case 'edit':
$entry = Entries::processEntry(PATH['entries'] . '/' . Http::get('entry') . '/entry.html', false, true);
if (Http::get('media') && Http::get('media') == 'true') {
EntriesManager::processFilesManager();
Themes::view('admin/views/templates/content/entries/media')
->assign('entry_name', Http::get('entry'))
->assign('files', EntriesManager::getMediaList(Http::get('entry')), true)
->assign('entry', $entry)
->display();
} else {
if (Http::get('source') && Http::get('source') == 'true') {
$action = Http::post('action');
if (isset($action) && $action == 'save-form') {
if (Token::check((Http::post('token')))) {
Filesystem::setFileContent(
PATH['entries'] . '/' . Http::post('entry_name') . '/entry.html',
Http::post('entry_content')
);
Notification::set('success', __('admin_message_entry_changes_saved'));
Http::redirect(Http::getBaseUrl().'/admin/entries/edit?entry='.Http::post('entry_name').'&source=true');
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
$entry_content = Filesystem::getFileContent(PATH['entries'] . '/' . Http::get('entry') . '/entry.html');
Themes::view('admin/views/templates/content/entries/source')
->assign('entry_name', Http::get('entry'))
->assign('entry_content', $entry_content)
->assign('entry', $entry)
->assign('files', EntriesManager::getMediaList(Http::get('entry')), true)
->display();
} else {
$action = Http::post('action');
$indenter = new Indenter();
if (isset($action) && $action == 'save-form') {
if (Token::check((Http::post('token')))) {
$entry = Entries::processEntry(PATH['entries'] . '/' . Http::get('entry') . '/entry.html', false, true);
Arr::delete($entry, 'content');
Arr::delete($entry, 'url');
Arr::delete($entry, 'slug');
Arr::delete($entry, 'base_url');
$frontmatter = $_POST;
Arr::delete($frontmatter, 'token');
Arr::delete($frontmatter, 'action');
Arr::delete($frontmatter, 'content');
$frontmatter = YamlParser::encode(array_merge($entry, $frontmatter));
$content = Http::post('content');
$content = (isset($content)) ? $indenter->indent($content) : '';
Filesystem::setFileContent(
PATH['entries'] . '/' . Http::get('entry') . '/entry.html',
'---'."\n".
$frontmatter."\n".
'---'."\n".
$content
);
Notification::set('success', __('admin_message_entry_changes_saved'));
Http::redirect(Http::getBaseUrl().'/admin/entries/edit?entry='.Http::get('entry'));
}
}
// Fieldset for current entry template
$fieldset_path = PATH['themes'] . '/' . Registry::get('settings.theme') . '/fieldsets/' . (isset($entry['fieldset']) ? $entry['fieldset'] : 'default') . '.yaml';
$fieldset = YamlParser::decode(Filesystem::getFileContent($fieldset_path));
is_null($fieldset) and $fieldset = [];
Themes::view('admin/views/templates/content/entries/content')
->assign('entry_name', Http::get('entry'))
->assign('entry', $entry)
->assign('fieldset', $fieldset)
->assign('templates', Themes::getTemplates())
->assign('files', EntriesManager::getMediaList(Http::get('entry')), true)
->display();
}
}
break;
default:
if (!Http::get('add')) {
Themes::view('admin/views/templates/content/entries/list')
->assign('entries_list', Entries::getEntries($query, 'date', 'DESC'))
->display();
}
break;
}
}
public static function getMediaList($entry, $path = false)
{
$files = [];
foreach (array_diff(scandir(PATH['entries'] . '/' . $entry), ['..', '.']) as $file) {
if (strpos(Registry::get('settings.entries.media.accept_file_types'), $file_ext = substr(strrchr($file, '.'), 1)) !== false) {
if (strpos($file, strtolower($file_ext), 1)) {
if ($path) {
$files[Http::getBaseUrl().'/'.$entry.'/'.$file] = Http::getBaseUrl().'/'.$entry.'/'.$file;
} else {
$files[$file] = $file;
}
}
}
}
return $files;
}
public static function displayEntryForm(array $form, array $values = [], string $content)
{
echo Form::open(null, ['id' => 'form', 'class' => 'row']);
echo Form::hidden('token', Token::generate());
echo Form::hidden('action', 'save-form');
if (isset($form) > 0) {
foreach ($form as $element => $property) {
// Create attributes
$property['attributes'] = Arr::keyExists($property, 'attributes') ? $property['attributes'] : [] ;
// Create attribute class
$property['attributes']['class'] = Arr::keyExists($property, 'attributes.class') ? 'form-control ' . $property['attributes']['class'] : 'form-control' ;
// Create attribute size
$property['size'] = Arr::keyExists($property, 'size') ? $property['size'] : 'col-12' ;
// Create attribute value
$property['value'] = Arr::keyExists($property, 'value') ? $property['value'] : '' ;
$pos = strpos($element, '.');
if ($pos === false) {
$form_element_name = $element;
} else {
$form_element_name = str_replace(".", "][", "$element").']';
}
$pos = strpos($form_element_name, ']');
if ($pos !== false) {
$form_element_name = substr_replace($form_element_name, '', $pos, strlen(']'));
}
// Form value
$form_value = Arr::keyExists($values, $element) ? Arr::get($values, $element) : $property['value'];
// Form label
$form_label = Form::label($element, __($property['title']));
// Form elements
switch ($property['type']) {
// Simple text-input, for multi-line fields.
case 'textarea':
$form_element = Form::textarea($element, $form_value, $property['attributes']);
break;
// The hidden field is like the text field, except it's hidden from the content editor.
case 'hidden':
$form_element = Form::hidden($element, $form_value);
break;
// A WYSIWYG HTML field.
case 'html':
$property['attributes']['class'] .= ' js-html-editor';
$form_element = Form::textarea($element, $form_value, $property['attributes']);
break;
// A specific WYSIWYG HTML field for entry content editing
case 'content':
$form_element = Form::textarea($element, $content, $property['attributes']);
break;
// Template select field for selecting entry template
case 'template_select':
$form_element = Form::select($form_element_name, Themes::getTemplates(), $form_value, $property['attributes']);
break;
// Visibility select field for selecting entry visibility state
case 'visibility_select':
$form_element = Form::select($form_element_name, ['draft' => __('admin_entries_draft'), 'visible' => __('admin_entries_visible'), 'hidden' => __('admin_entries_hidden')], (!empty($form_value) ? $form_value : 'visible'), $property['attributes']);
break;
// Media select field
case 'media_select':
$form_element = Form::select($form_element_name, EntriesManager::getMediaList(Http::get('entry'), false), $form_value, $property['attributes']);
break;
// Simple text-input, for single-line fields.
default:
$form_element = Form::input($form_element_name, $form_value, $property['attributes']);
break;
}
// Render form elments with labels
if ($property['type'] == 'hidden') {
echo $form_element;
} else {
echo '<div class="form-group '.$property['size'].'">';
echo $form_label . $form_element;
echo '</div>';
}
}
}
echo Form::close();
}
protected static function processFilesManager()
{
$files_directory = PATH['entries'] . '/' . Http::get('entry') . '/';
if (Http::get('delete_file') != '') {
if (Token::check((Http::get('token')))) {
Filesystem::deleteFile($files_directory . Http::get('delete_file'));
Notification::set('success', __('admin_message_entry_file_deleted'));
Http::redirect(Http::getBaseUrl().'/admin/entries/edit?entry='.Http::get('entry').'&media=true');
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
if (Http::post('upload_file')) {
if (Token::check(Http::post('token'))) {
//echo Registry::get('settings.entries.media.accept_file_types');
$file = EntriesManager::uploadFile($_FILES['file'], $files_directory, Registry::get('settings.entries.media.accept_file_types'), 27000000);
if($file !== false) {
if (in_array(pathinfo($file)['extension'], ['jpg', 'jpeg', 'png', 'gif'])) {
// open an image file
$img = Image::make($file);
// now you are able to resize the instance
if (Registry::get('settings.entries.media.upload_images_width') > 0 && Registry::get('settings.entries.media.upload_images_height') > 0) {
$img->resize(Registry::get('settings.entries.media.upload_images_width'), Registry::get('settings.entries.media.upload_images_height'), function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
});
} elseif (Registry::get('settings.entries.media.upload_images_width') > 0) {
$img->resize(Registry::get('settings.entries.media.upload_images_width'), null, function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
});
} elseif (Registry::get('settings.entries.media.upload_images_height') > 0) {
$img->resize(null, Registry::get('settings.entries.media.upload_images_height'), function ($constraint) {
$constraint->aspectRatio();
$constraint->upsize();
});
}
// finally we save the image as a new file
$img->save($file, Registry::get('settings.entries.media.upload_images_quality'));
// destroy
$img->destroy();
}
Notification::set('success', __('admin_message_entry_file_uploaded'));
Http::redirect(Http::getBaseUrl().'/admin/entries/edit?entry='.Http::get('entry').'&media=true');
} else {
Notification::set('error', __('admin_message_entry_file_not_uploaded'));
Http::redirect(Http::getBaseUrl().'/admin/entries/edit?entry='.Http::get('entry').'&media=true');
}
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
}
/**
* Upload files on the Server with several type of Validations!
*
* Entries::uploadFile($_FILES['file'], $files_directory);
*
* @param array $file Uploaded file data
* @param string $upload_directory Upload directory
* @param string $allowed Allowed file extensions
* @param int $max_size Max file size in bytes
* @param string $filename New filename
* @param bool $remove_spaces Remove spaces from the filename
* @param int $max_width Maximum width of image
* @param int $max_height Maximum height of image
* @param bool $exact Match width and height exactly?
* @param int $chmod Chmod mask
* @return string on success, full path to new file
* @return false on failure
*/
public static function uploadFile(
array $file,
string $upload_directory,
string $allowed = 'jpeg, png, gif, jpg',
int $max_size = 3000000,
string $filename = null,
bool $remove_spaces = true,
int $max_width = null,
int $max_height = null,
bool $exact = false,
int $chmod = 0644
) {
//
// Tests if a successful upload has been made.
//
if (isset($file['error'])
and isset($file['tmp_name'])
and $file['error'] === UPLOAD_ERR_OK
and is_uploaded_file($file['tmp_name'])) {
//
// Tests if upload data is valid, even if no file was uploaded.
//
if (isset($file['error'])
and isset($file['name'])
and isset($file['type'])
and isset($file['tmp_name'])
and isset($file['size'])) {
//
// Test if an uploaded file is an allowed file type, by extension.
//
if (strpos($allowed, strtolower(pathinfo($file['name'], PATHINFO_EXTENSION))) !== false) {
//
// Validation rule to test if an uploaded file is allowed by file size.
//
if (($file['error'] != UPLOAD_ERR_INI_SIZE)
and ($file['error'] == UPLOAD_ERR_OK)
and ($file['size'] <= $max_size)) {
//
// Validation rule to test if an upload is an image and, optionally, is the correct size.
//
if (in_array(mime_content_type($file['tmp_name']), ['image/jpeg', 'image/jpg', 'image/png','image/gif'])) {
function validateImage($file, $max_width, $max_height, $exact)
{
try {
// Get the width and height from the uploaded image
list($width, $height) = getimagesize($file['tmp_name']);
} catch (ErrorException $e) {
// Ignore read errors
}
if (empty($width) or empty($height)) {
// Cannot get image size, cannot validate
return false;
}
if (! $max_width) {
// No limit, use the image width
$max_width = $width;
}
if (! $max_height) {
// No limit, use the image height
$max_height = $height;
}
if ($exact) {
// Check if dimensions match exactly
return ($width === $max_width and $height === $max_height);
} else {
// Check if size is within maximum dimensions
return ($width <= $max_width and $height <= $max_height);
}
return false;
}
if (validateImage($file, $max_width, $max_height, $exact) === false) {
return false;
}
}
if (! isset($file['tmp_name']) or ! is_uploaded_file($file['tmp_name'])) {
// Ignore corrupted uploads
return false;
}
if ($filename === null) {
// Use the default filename
$filename = $file['name'];
}
if ($remove_spaces === true) {
// Remove spaces from the filename
$filename = Text::safeString(pathinfo($filename)['filename'], '-', true) . '.' . pathinfo($filename)['extension'];
}
if (! is_dir($upload_directory) or ! is_writable(realpath($upload_directory))) {
throw new \RuntimeException("Directory {$upload_directory} must be writable");
}
// Make the filename into a complete path
$filename = realpath($upload_directory).DIRECTORY_SEPARATOR.$filename;
if (move_uploaded_file($file['tmp_name'], $filename)) {
if ($chmod !== false) {
// Set permissions on filename
chmod($filename, $chmod);
}
// Return new file path
return $filename;
}
}
}
}
}
return false;
}
}

View File

@@ -1,133 +0,0 @@
<?php
namespace Flextype;
use Flextype\Component\Registry\Registry;
use Flextype\Component\Http\Http;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Token\Token;
use Flextype\Component\Text\Text;
use Flextype\Component\Notification\Notification;
use function Flextype\Component\I18n\__;
class FieldsetsManager
{
public static function getFieldsetsManager()
{
Registry::set('sidebar_menu_item', 'fieldsets');
switch (Http::getUriSegment(2)) {
case 'add':
$create_fieldset = Http::post('create_fieldset');
if (isset($create_fieldset)) {
if (Token::check((Http::post('token')))) {
$file = PATH['themes'] . '/' . Registry::get('settings.theme') . '/fieldsets/' . Text::safeString(Http::post('name'), '-', true) . '.yaml';
if (!Filesystem::fileExists($file)) {
// Create a fieldset!
if (Filesystem::setFileContent(
$file,
YamlParser::encode([
'title' => Http::post('title'),
'fields' => [
'title' => [
'title' => 'admin_title',
'type' => 'text',
'size' => 'col-12'
]
]
])
)) {
Notification::set('success', __('admin_message_fieldset_created'));
Http::redirect(Http::getBaseUrl() . '/admin/fieldsets');
}
}
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
Themes::view('admin/views/templates/extends/fieldsets/add')
->display();
break;
case 'delete':
if (Http::get('fieldset') != '') {
if (Token::check((Http::get('token')))) {
Filesystem::deleteFile(PATH['themes'] . '/' . Registry::get('settings.theme') . '/fieldsets/' . Http::get('fieldset') . '.yaml');
Notification::set('success', __('admin_message_fieldset_deleted'));
Http::redirect(Http::getBaseUrl() . '/admin/fieldsets');
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
break;
case 'rename':
$rename_fieldset = Http::post('rename_fieldset');
if (isset($rename_fieldset)) {
if (Token::check((Http::post('token')))) {
if (!Filesystem::fileExists(PATH['themes'] . '/' . Registry::get('settings.theme') . '/fieldsets/' . Http::post('name') . '.yaml')) {
if (rename(
PATH['themes'] . '/' . Registry::get('settings.theme') . '/fieldsets/' . Http::post('name_current') . '.yaml',
PATH['themes'] . '/' . Registry::get('settings.theme') . '/fieldsets/' . Http::post('name') . '.yaml')
) {
Notification::set('success', __('admin_message_fieldset_renamed'));
Http::redirect(Http::getBaseUrl() . '/admin/fieldsets');
}
}
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
Themes::view('admin/views/templates/extends/fieldsets/rename')
->assign('name_current', Http::get('fieldset'))
->display();
break;
case 'duplicate':
if (Http::get('fieldset') != '') {
if (Token::check((Http::get('token')))) {
Filesystem::copy(PATH['themes'] . '/' . Registry::get('settings.theme') . '/fieldsets/' . Http::get('fieldset') . '.yaml',
PATH['themes'] . '/' . Registry::get('settings.theme') . '/fieldsets/' . Http::get('fieldset') . '-duplicate-' . date("Ymd_His") . '.yaml');
Notification::set('success', __('admin_message_fieldset_duplicated'));
Http::redirect(Http::getBaseUrl().'/admin/fieldsets');
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
break;
case 'edit':
$action = Http::post('action');
if (isset($action) && $action == 'save-form') {
if (Token::check((Http::post('token')))) {
// Save a fieldset!
if (Filesystem::setFileContent(
PATH['themes'] . '/' . Registry::get('settings.theme') . '/fieldsets/' . Http::post('name') . '.yaml',
Http::post('fieldset')
)) {
Notification::set('success', __('admin_message_fieldset_saved'));
Http::redirect(Http::getBaseUrl() . '/admin/fieldsets/edit?fieldset='.Http::post('name'));
}
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
Themes::view('admin/views/templates/extends/fieldsets/edit')
->assign('fieldset', Filesystem::getFileContent(PATH['themes'] . '/' . Registry::get('settings.theme') . '/fieldsets/' . Http::get('fieldset') . '.yaml'))
->display();
break;
default:
$fieldsets_list = Themes::getFieldsets();
Themes::view('admin/views/templates/extends/fieldsets/list')
->assign('fieldsets_list', $fieldsets_list)
->display();
break;
}
}
}

View File

@@ -1,14 +0,0 @@
<?php
namespace Flextype;
use Flextype\Component\Registry\Registry;
class InformationManager
{
public static function getInformationManager()
{
Registry::set('sidebar_menu_item', 'infomation');
Themes::view('admin/views/templates/system/information/list')->display();
}
}

View File

@@ -1,136 +0,0 @@
<?php
namespace Flextype;
use Flextype\Component\Registry\Registry;
use Flextype\Component\Http\Http;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Token\Token;
use Flextype\Component\Text\Text;
use Flextype\Component\Notification\Notification;
use function Flextype\Component\I18n\__;
class MenusManager
{
public static function getMenusManager()
{
Registry::set('sidebar_menu_item', 'menus');
// Create directory for menus
!Filesystem::fileExists(PATH['menus']) and Filesystem::createDir(PATH['menus']);
switch (Http::getUriSegment(2)) {
case 'add':
$create_menu = Http::post('create_menu');
if (isset($create_menu)) {
if (Token::check((Http::post('token')))) {
$file = PATH['menus'] . '/' . Text::safeString(Http::post('name'), '-', true) . '.yaml';
if (!Filesystem::fileExists($file)) {
// Create a menu!
if (Filesystem::setFileContent(
$file,
YamlParser::encode(['title' => Http::post('title')])
)) {
Notification::set('success', __('admin_message_menu_created'));
Http::redirect(Http::getBaseUrl() . '/admin/menus');
}
}
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
Themes::view('admin/views/templates/extends/menus/add')
->display();
break;
case 'delete':
if (Http::get('menu') != '') {
if (Token::check((Http::get('token')))) {
Filesystem::deleteFile(PATH['menus'] . '/' . Http::get('menu') . '.yaml');
Notification::set('success', __('admin_message_menu_deleted'));
Http::redirect(Http::getBaseUrl() . '/admin/menus');
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
break;
case 'rename':
$rename_menu = Http::post('rename_menu');
if (isset($rename_menu)) {
if (Token::check((Http::post('token')))) {
if (!Filesystem::fileExists(PATH['menus'] . '/' . Http::post('name') . '.yaml')) {
if (rename(
PATH['menus'] . '/' . Http::post('name_current') . '.yaml',
PATH['menus'] . '/' . Http::post('name') . '.yaml')
) {
Notification::set('success', __('admin_message_menu_renamed'));
Http::redirect(Http::getBaseUrl() . '/admin/menus');
}
}
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
Themes::view('admin/views/templates/extends/menus/rename')
->assign('name_current', Http::get('menu'))
->display();
break;
case 'duplicate':
if (Http::get('menu') != '') {
if (Token::check((Http::get('token')))) {
Filesystem::copy(PATH['menus'] . '/' . Http::get('menu') . '.yaml',
PATH['menus'] . '/' . Http::get('menu') . '-duplicate-' . date("Ymd_His") . '.yaml');
Notification::set('success', __('admin_message_menu_duplicated'));
Http::redirect(Http::getBaseUrl().'/admin/menus');
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
break;
case 'edit':
$action = Http::post('action');
if (isset($action) && $action == 'save-form') {
if (Token::check((Http::post('token')))) {
// Save a menu!
if (Filesystem::setFileContent(
PATH['menus'] . '/' . Http::post('name') . '.yaml',
Http::post('menu')
)) {
Notification::set('success', __('admin_message_menu_saved'));
Http::redirect(Http::getBaseUrl() . '/admin/menus/edit?menu=' . Http::post('name'));
}
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
Themes::view('admin/views/templates/extends/menus/edit')
->assign('menu', Filesystem::getFileContent(PATH['menus'] . '/' . Http::get('menu') . '.yaml'))
->display();
break;
default:
$menus = [];
$menus_list = [];
$menus = Filesystem::getFilesList(PATH['menus'], 'yaml');
if (count($menus) > 0) {
foreach ($menus as $menu) {
$menus_list[basename($menu, '.yaml')] = YamlParser::decode(Filesystem::getFileContent($menu));
}
}
Themes::view('admin/views/templates/extends/menus/list')
->assign('menus_list', $menus_list)
->display();
break;
}
}
}

View File

@@ -1,22 +0,0 @@
<?php
namespace Flextype;
use Flextype\Component\Registry\Registry;
class NavigationManager
{
public static function addItem(string $area, string $item, string $title, string $link, array $attributes = [])
{
Registry::set("admin_navigation.{$area}.{$item}.area", $area);
Registry::set("admin_navigation.{$area}.{$item}.item", $item);
Registry::set("admin_navigation.{$area}.{$item}.title", $title);
Registry::set("admin_navigation.{$area}.{$item}.link", $link);
Registry::set("admin_navigation.{$area}.{$item}.attributes", $attributes);
}
public static function getItems(string $area)
{
return Registry::get("admin_navigation.{$area}");
}
}

View File

@@ -1,45 +0,0 @@
<?php
namespace Flextype;
use Flextype\Component\Arr\Arr;
use Flextype\Component\Http\Http;
use Flextype\Component\Event\Event;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Registry\Registry;
use Flextype\Component\Token\Token;
class PluginsManager
{
/**
* _pluginsChangeStatusAjax
*/
public static function _pluginsChangeStatusAjax()
{
if (Http::post('plugin_change_status')) {
if (Token::check((Http::post('token')))) {
$plugin_settings = YamlParser::decode(Filesystem::getFileContent(PATH['plugins'] . '/' . Http::post('plugin') . '/' . 'settings.yaml'));
Arr::set($plugin_settings, 'enabled', (Http::post('status') == 'true' ? true : false));
Filesystem::setFileContent(PATH['plugins'] . '/' . Http::post('plugin') . '/' . 'settings.yaml', YamlParser::encode($plugin_settings));
Cache::clear();
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
}
public static function getPluginsManager()
{
Registry::set('sidebar_menu_item', 'plugins');
Event::addListener('onBeforeRequestShutdown', function () {
PluginsManager::_pluginsChangeStatusAjax();
});
Themes::view('admin/views/templates/extends/plugins/list')
->assign('plugins_list', Registry::get('plugins'))
->display();
}
}

View File

@@ -1,104 +0,0 @@
<?php
namespace Flextype;
use Flextype\Component\Arr\Arr;
use Flextype\Component\Number\Number;
use Flextype\Component\I18n\I18n;
use Flextype\Component\Http\Http;
use Flextype\Component\Event\Event;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Session\Session;
use Flextype\Component\Registry\Registry;
use Flextype\Component\Token\Token;
use Flextype\Component\Text\Text;
use Flextype\Component\Form\Form;
use Flextype\Component\Notification\Notification;
use function Flextype\Component\I18n\__;
use Gajus\Dindent\Indenter;
class SettingsManager
{
public static function getSettingsManager()
{
Registry::set('sidebar_menu_item', 'settings');
// Clear cache
if (Http::get('clear_cache')) {
if (Token::check((Http::get('token')))) {
Cache::clear();
Notification::set('success', __('admin_message_cache_files_deleted'));
Http::redirect(Http::getBaseUrl().'/admin/settings');
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
$action = Http::post('action');
if (isset($action) && $action == 'save-form') {
if (Token::check((Http::post('token')))) {
$settings = $_POST;
Arr::delete($settings, 'token');
Arr::delete($settings, 'action');
Arr::set($settings, 'errors.display', (Http::post('errors.display') == '1' ? true : false));
Arr::set($settings, 'cache.enabled', (Http::post('cache.enabled') == '1' ? true : false));
Arr::set($settings, 'cache.lifetime', (int) Http::post('cache.lifetime'));
Arr::set($settings, 'entries.media.upload_images_quality', (int) Http::post('entries.media.upload_images_quality'));
Arr::set($settings, 'entries.media.upload_images_width', (int) Http::post('entries.media.upload_images_width'));
Arr::set($settings, 'entries.media.upload_images_height', (int) Http::post('entries.media.upload_images_height'));
if (Filesystem::setFileContent(PATH['config']['site'] . '/settings.yaml', YamlParser::encode(array_merge(Registry::get('settings'), $settings)))) {
Notification::set('success', __('admin_message_settings_saved'));
Http::redirect(Http::getBaseUrl().'/admin/settings');
}
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
$available_locales = Filesystem::getFilesList(PATH['plugins'] . '/admin/languages/', 'yaml');
$system_locales = Plugins::getLocales();
$locales = [];
foreach ($available_locales as $locale) {
$locales[basename($locale, '.yaml')] = $system_locales[basename($locale, '.yaml')];
}
$entries = [];
foreach (Entries::getEntries('', 'date', 'DESC') as $entry) {
$entries[$entry['slug']] = $entry['title'];
}
$themes = [];
foreach (Filesystem::getDirList(PATH['themes']) as $theme) {
$themes[$theme] = $theme;
}
$cache_driver = ['auto' => 'Auto Detect',
'file' => 'File',
'apc' => 'APC',
'apcu' => 'APCu',
'wincache' => 'WinCache',
'xcache' => 'Xcache',
'memcache' => 'Memcache',
'memcached' => 'Memcached',
'redis' => 'Redis',
'sqlite3' => 'SQLite3',
'zend' => 'Zend',
'array' => 'Array'];
Themes::view('admin/views/templates/system/settings/list')
->assign('settings', Registry::get('settings'))
->assign('cache_driver', $cache_driver)
->assign('locales', $locales)
->assign('entries', $entries)
->assign('themes', $themes)
->display();
}
}

View File

@@ -1,127 +0,0 @@
<?php
namespace Flextype;
use Flextype\Component\Registry\Registry;
use Flextype\Component\Http\Http;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Token\Token;
use Flextype\Component\Text\Text;
use Flextype\Component\Notification\Notification;
use function Flextype\Component\I18n\__;
class SnippetsManager
{
public static function getSnippetsManager()
{
Registry::set('sidebar_menu_item', 'snippets');
// Create directory for logs
!Filesystem::fileExists(PATH['snippets']) and Filesystem::createDir(PATH['snippets']);
switch (Http::getUriSegment(2)) {
case 'add':
$create_snippet = Http::post('create_snippet');
if (isset($create_snippet)) {
if (Token::check((Http::post('token')))) {
$file = PATH['snippets'] . '/' . Text::safeString(Http::post('name'), '-', true) . '.php';
if (!Filesystem::fileExists($file)) {
// Create a snippet!
if (Filesystem::setFileContent(
$file,
""
)) {
Notification::set('success', __('admin_message_snippet_created'));
Http::redirect(Http::getBaseUrl() . '/admin/snippets');
}
}
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
Themes::view('admin/views/templates/extends/snippets/add')
->display();
break;
case 'delete':
if (Http::get('snippet') != '') {
if (Token::check((Http::get('token')))) {
Filesystem::deleteFile(PATH['snippets'] . '/' . Http::get('snippet') . '.php');
Notification::set('success', __('admin_message_snippet_deleted'));
Http::redirect(Http::getBaseUrl() . '/admin/snippets');
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
break;
case 'rename':
$rename_snippet = Http::post('rename_snippet');
if (isset($rename_snippet)) {
if (Token::check((Http::post('token')))) {
if (!Filesystem::fileExists(PATH['snippets'] . '/' . Http::post('name') . '.php')) {
if (rename(
PATH['snippets'] . '/' . Http::post('name_current') . '.php',
PATH['snippets'] . '/' . Http::post('name') . '.php')
) {
Notification::set('success', __('admin_message_snippet_renamed'));
Http::redirect(Http::getBaseUrl() . '/admin/snippets');
}
}
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
Themes::view('admin/views/templates/extends/snippets/rename')
->assign('name_current', Http::get('snippet'))
->display();
break;
case 'duplicate':
if (Http::get('snippet') != '') {
if (Token::check((Http::get('token')))) {
Filesystem::copy(PATH['snippets'] . '/' . Http::get('snippet') . '.php',
PATH['snippets'] . '/' . Http::get('snippet') . '-duplicate-' . date("Ymd_His") . '.php');
Notification::set('success', __('admin_message_snippet_duplicated'));
Http::redirect(Http::getBaseUrl().'/admin/snippets');
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
break;
case 'edit':
$action = Http::post('action');
if (isset($action) && $action == 'save-form') {
if (Token::check((Http::post('token')))) {
// Save a snippet!
if (Filesystem::setFileContent(
PATH['snippets'] . '/' . Http::post('name') . '.php',
Http::post('snippet')
)) {
Notification::set('success', __('admin_message_snippet_saved'));
Http::redirect(Http::getBaseUrl() . '/admin/snippets/edit?snippet='.Http::post('name'));
}
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
Themes::view('admin/views/templates/extends/snippets/edit')
->assign('snippet', Filesystem::getFileContent(PATH['snippets'] . '/' . Http::get('snippet') . '.php'))
->display();
break;
default:
$snippets_list = Filesystem::getFilesList(PATH['snippets'], 'php');
Themes::view('admin/views/templates/extends/snippets/list')
->assign('snippets_list', $snippets_list)
->display();
break;
}
}
}

View File

@@ -1,136 +0,0 @@
<?php
namespace Flextype;
use Flextype\Component\Registry\Registry;
use Flextype\Component\Http\Http;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Token\Token;
use Flextype\Component\Text\Text;
use Flextype\Component\Notification\Notification;
use function Flextype\Component\I18n\__;
class TemplatesManager
{
public static function getTemplatesManager()
{
Registry::set('sidebar_menu_item', 'templates');
switch (Http::getUriSegment(2)) {
case 'add':
$create_template = Http::post('create_template');
if (isset($create_template)) {
if (Token::check((Http::post('token')))) {
$type = (Http::post('type') && Http::post('type') == 'partial') ? 'partial' : 'template';
$file = PATH['themes'] . '/' . Registry::get('settings.theme') . '/views/' . $type . 's' . '/' . Text::safeString(Http::post('name'), '-', true) . '.php';
if (!Filesystem::fileExists($file)) {
// Create a template!
if (Filesystem::setFileContent(
$file,
""
)) {
Notification::set('success', __('admin_message_template_created'));
Http::redirect(Http::getBaseUrl() . '/admin/templates');
}
}
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
Themes::view('admin/views/templates/extends/templates/add')
->display();
break;
case 'delete':
if (Http::get('template') != '') {
if (Token::check((Http::get('token')))) {
$type = (Http::get('type') && Http::get('type') == 'partial') ? 'partial' : 'template';
Filesystem::deleteFile(PATH['themes'] . '/' . Registry::get('settings.theme') . '/views/' . $type . 's' . '/' . Http::get('template') . '.php');
Notification::set('success', __('admin_message_template_deleted'));
Http::redirect(Http::getBaseUrl() . '/admin/templates');
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
break;
case 'rename':
$rename_template = Http::post('rename_template');
if (isset($rename_template)) {
if (Token::check((Http::post('token')))) {
$type = (Http::post('type') && Http::post('type') == 'partial') ? 'partial' : 'template';
$type_current = (Http::post('type_current') && Http::post('type_current') == 'partial') ? 'partial' : 'template';
if (!Filesystem::fileExists(PATH['themes'] . '/' . Registry::get('settings.theme') . '/views/' . $type . 's' . '/' . Http::post('name') . '.php')) {
if (rename(
PATH['themes'] . '/' . Registry::get('settings.theme') . '/views/' . $type_current . 's' . '/' . Http::post('name_current') . '.php',
PATH['themes'] . '/' . Registry::get('settings.theme') . '/views/' . $type . 's' . '/' . Http::post('name') . '.php')
) {
Notification::set('success', __('admin_message_template_renamed'));
Http::redirect(Http::getBaseUrl() . '/admin/templates');
}
}
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
Themes::view('admin/views/templates/extends/templates/rename')
->assign('name_current', Http::get('template'))
->assign('type', ((Http::get('type') && Http::get('type') == 'partial') ? 'partial' : 'template'))
->display();
break;
case 'duplicate':
if (Http::get('template') != '') {
if (Token::check((Http::get('token')))) {
$type = (Http::get('type') && Http::get('type') == 'partial') ? 'partial' : 'template';
Filesystem::copy(PATH['themes'] . '/' . Registry::get('settings.theme') . '/views/' . $type . 's' . '/' . Http::get('template') . '.php',
PATH['themes'] . '/' . Registry::get('settings.theme') . '/views/' . $type . 's' . '/' . Http::get('template') . '-duplicate-' . date("Ymd_His") . '.php');
Notification::set('success', __('admin_message_template_duplicated'));
Http::redirect(Http::getBaseUrl().'/admin/templates');
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
break;
case 'edit':
$action = Http::post('action');
if (isset($action) && $action == 'save-form') {
if (Token::check((Http::post('token')))) {
$type = (Http::post('type') && Http::post('type') == 'partial') ? 'partial' : 'template';
// Save a template!
if (Filesystem::setFileContent(
PATH['themes'] . '/' . Registry::get('settings.theme') . '/views/' . $type . 's' . '/' . Http::post('name') . '.php',
Http::post('template')
)) {
Notification::set('success', __('admin_message_template_saved'));
Http::redirect(Http::getBaseUrl() . '/admin/templates/edit?template=' . Http::post('name') . '&type=' . $type);
}
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
$type = (Http::get('type') && Http::get('type') == 'partial') ? 'partials' : 'templates';
Themes::view('admin/views/templates/extends/templates/edit')
->assign('template', Filesystem::getFileContent(PATH['themes'] . '/' . Registry::get('settings.theme') . '/views/' . $type . '/' . Http::get('template') . '.php'))
->assign('type', ((Http::get('type') && Http::get('type') == 'partial') ? 'partial' : 'template'))
->display();
break;
default:
Themes::view('admin/views/templates/extends/templates/list')
->assign('templates_list', Themes::getTemplates())
->assign('partials_list', Themes::getPartials())
->display();
break;
}
}
}

View File

@@ -1,107 +0,0 @@
<?php
namespace Flextype;
use Flextype\Component\Http\Http;
use Flextype\Component\Filesystem\Filesystem;
use Flextype\Component\Session\Session;
use Flextype\Component\Token\Token;
use Flextype\Component\Registry\Registry;
use Flextype\Component\Text\Text;
use Flextype\Component\Notification\Notification;
use function Flextype\Component\I18n\__;
class UsersManager
{
public static function getProfileManager()
{
Registry::set('sidebar_menu_item', 'profile');
Themes::view('admin/views/templates/users/profile')
->display();
}
public static function logout()
{
if (Token::check((Http::get('token')))) {
Session::destroy();
Http::redirect(Http::getBaseUrl().'/admin');
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
public static function getRegistrationPage()
{
Registry::set('sidebar_menu_item', '');
$registration = Http::post('registration');
if (isset($registration)) {
if (Token::check((Http::post('token')))) {
if (Filesystem::fileExists($_user_file = PATH['site'] . '/accounts/' . Text::safeString(Http::post('username')) . '.yaml')) {
} else {
Filesystem::setFileContent(
PATH['site'] . '/accounts/' . Http::post('username') . '.yaml',
YamlParser::encode(['username' => Text::safeString(Http::post('username')),
'hashed_password' => password_hash(trim(Http::post('password')), PASSWORD_BCRYPT),
'email' => Http::post('email'),
'role' => 'admin',
'state' => 'enabled'])
);
Http::redirect(Http::getBaseUrl().'/admin/entries');
}
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
Themes::view('admin/views/templates/auth/registration')
->display();
}
public static function isUsersExists()
{
// Get Users Profiles
$users = Filesystem::getFilesList(PATH['site'] . '/accounts/', 'yaml');
// If any users exists then return true
return ($users && count($users) > 0) ? true : false;
}
public static function isLoggedIn()
{
return (Session::exists('role') && Session::get('role') == 'admin') ? true : false;
}
public static function getAuthPage()
{
Registry::set('sidebar_menu_item', '');
$login = Http::post('login');
if (isset($login)) {
if (Token::check((Http::post('token')))) {
if (Filesystem::fileExists($_user_file = PATH['site'] . '/accounts/' . Http::post('username') . '.yaml')) {
$user_file = YamlParser::decode(Filesystem::getFileContent($_user_file));
if (password_verify(trim(Http::post('password')), $user_file['hashed_password'])) {
Session::set('username', $user_file['username']);
Session::set('role', $user_file['role']);
Http::redirect(Http::getBaseUrl().'/admin/entries');
} else {
Notification::set('error', __('admin_message_wrong_username_password'));
}
} else {
Notification::set('error', __('admin_message_wrong_username_password'));
}
} else {
die('Request was denied because it contained an invalid security token. Please refresh the page and try again.');
}
}
Themes::view('admin/views/templates/auth/login')
->display();
}
}

Some files were not shown because too many files have changed in this diff Show More