text:
<repo_name>Manchenkoff/deepkit-old<file_sep>/TODO.md
# TODO

- Users subscriptions relation DB
- Off-canvas menu -> only top level
- HTML Widgets from DB (Twig filter)
- Load meta into App object

# NOTES

- Create PHP class like ImageMagician (which based on GD) for work with images
- Replace TableSort with jQuery plugin
- pagination settings separately in each plugin

# FEATURES

- OAuth Authorization
- Google reCaptcha (comments, reviews, register)
<file_sep>/system/deepkit/helpers/FormHelper.php
<?php

	namespace deepkit\helpers;

	/**
	* Form validate and data process class
	*/
	class FormHelper {

		/**
		* Validate rules
		*
		* @var $patterns Associative array with 'key => /pattern/'
		*/
		public static $patterns = [
			'login' 		=> '^[a-zA-Z0-9_-]{3,30}$',
			'email' 		=> '^[A-z0-9]{4,}@[A-z0-9]{2,}\.[A-z]{2,}$',
			'telephone'		=> '^\+?(\d.*){4,}$',
			'title' 		=> '^[-_A-zА-яёЁ0-9\s()]{2,}$',
			'url' 			=> '^((https?|ftp|file):\/\/)?([\da-zа-яё\.-]+)\.([a-zа-яё\.]{2,6})([\/\w \.-?]*)*\/?$',
			'url_slug'		=> '^[a-z0-9-]+$',
			'int'	 		=> '^[0-9]+$',
			'float' 		=> '^[0-9.,]+$',
			'date'			=> '^(0?[1-9]|[12][0-9]|3[01])([ \/\-])(0?[1-9]|1[012])\2([0-9][0-9][0-9][0-9])(([ -])([0-1]?[0-9]|2[0-3]):[0-5]?[0-9]:[0-5]?[0-9])?$',
			'zip'			=> '^[0-9]{4,}$',
		];

		/**
		* Validate form function
		*
		* Function for check mathces of POST variables with current rules
		* Returns array with input names and errors
		*
		* Example:
		*
		* validateForm($_POST, [
		*	'firstname' 	=> ['name', 'required'],
		*	'login'			=> ['login', 'required'],
		*	'tel'			=> ['telephone', 'required'],
		*	'created_date'	=> ['date', 'required']
		* ]);
		*
		*	Code example for show form error
		*
		*	{% if post and not post.email %}
		*	Invalid value!
		*	{% endif %}
		*
		* @param array $post
		* @param array $rules
		*
		*/
		public static function validateForm($post, $rules) {
			// set base validation array
			$validation = [
				'valid'		=> true,
				'errors'	=> [],
				'post'		=> []
			];

			// validate each key-value pair
			foreach ($post as $key => $value) {
				// if pattern exists
				if (isset( $rules[$key][0] )) {
					// start validate value
					if (FormHelper::validateData($value, FormHelper::$patterns[ $rules[$key][0] ])) {
						// append new value to correct array
						$validation['post'][$key] = $value;
					} else {
						// if value is required
						if (isset($rules[$key][1]) && $rules[$key][1] == "required") {
							// set valid state false
							$validation['valid'] = false;
							array_push($validation['errors'], $key);
						} else {
							// set value to empty string
							$validation['post'][$key] = "";
						}
					}
				}
			}

			// return array validation
			return $validation;
		}

		/**
		* Validate data
		*
		* Validating one variable by selected pattern
		*
		* @param string $input -> content string
		* @param string $pattern -> replacement pattern
		*/
		private static function validateData($input, $pattern) {
			// check pattern matching
			return (preg_match("/{$pattern}/", $input)) ? true : false;
		}

		/**
		 * Start checking CSRF key valid
		 *
		 * @param array $post -> form $_POST object
		 */
		public static function CSRF_check($post) {
            $token = isset($post['token']) ? $post['token'] : '';

            if ($token == $_SESSION['token']) {
                return true;
            } else {
                \deepkit\helpers\ErrorHelper::showError('Security', 'Token invalid');
            }
        }

	}
<file_sep>/system/deepkit/core/PluginManager.php
<?php

	namespace deepkit\core;

	/**
	* Plugin manager class for process plugin behavior
	*/
	class PluginManager {

		/**
		 * Directory of plugins files
		 *
		 * (default value: PATH . "/plugins")
		 *
		 * @var string
		 */
		private $plugins_directory = PATH . "/plugins";

		/**
		 * Array of enabled plugins
		 *
		 * (default value: [])
		 *
		 * @var mixed
		 */
		public $plugins = [];

		/**
		 * Main init function
		 * Scan and start register all founded directories
		 *
		 * @return void
		 */
		function __construct() {
			// check directory exists
			if (!is_dir($this->plugins_directory)) return;

			// scan plugins
			$plugins_list = array_diff(scandir($this->plugins_directory), ['.', '..', '.DS_Store']);

			// register plugins
			foreach ($plugins_list as $plugin_name) {
				$dir = "{$this->plugins_directory}/{$plugin_name}";

				if (is_dir($dir)) {
					$this->register($plugin_name);
				}
			}
		}

		/**
		 * Register plugin function by include config file
		 *
		 * @param mixed $plugin_name
		 * @return void
		 */
		private function register($plugin_name) {
			$config_file = "{$this->plugins_directory}/{$plugin_name}/config.php";

			if (file_exists($config_file)) {
				$plugin = include($config_file);

				if ($plugin['enabled']) {
					$this->plugins[$plugin_name] = $plugin;
				}
			}
		}

	}
<file_sep>/system/config/app.php
<?php

	return array(

	    // Version info
        'application' => [
            'version' => '0.1',
        ],

		// Database connection settings
		'database' => [
			'host' 		=> 'localhost',
			'user' 		=> 'root',
			'password' 	=> '',
			'database' 	=> 'dk_cmf',
		],

		// Twig templater config
		'twig' => [
			'templates' => [
				PATH . '/app',
				PATH . '/plugins',
				PATH . '/app/common/views'
			],

			// module params
			'params' => [
				//'cache' => 'assets/twig_cache', 	// production only
				'debug' => true, 					// development only
				//'autoreload' => true,				// update templates if debug disabled
			],
		],

		// Debug properties (development only)
		'debug' => [
			'show_toolbar' 	=> false,
			'show_errors' 	=> 'on',
			'error_types' 	=> E_ALL,
		],

		// Module generator settings
		'generator' => [
			'enabled' => true,
		],

		// Session properties
		'session' => [
			'name'		=> 'deepkit',
			'http_only' => 'true',
			'life_time' => strtotime('+10 days'),
		],

		// App security settings
		'security' => [
			'salt' 		=> '44d0dbe034e921bc14535c5b892e56a9',
			'hash_type' => 'sha256',
			'csrf'		=> hash('sha256', uniqid(mt_rand(), true)),
		],

		'paths' => [ /* CHANGE TO: HOST, ROOT, HOST_DIR, DIR */
			// root paths
			'base_url'		=> $_SERVER['HTTP_HOST'],
			'base_dir'		=> $_SERVER['DOCUMENT_ROOT'],

			// relative URL (with subdirectory name)
			'relative_url'	=> $_SERVER['HTTP_HOST'].preg_replace("[\\\]", "/", dirname($_SERVER['PHP_SELF'])),
			// subdirectory name
			'subdirectory'	=> dirname($_SERVER['PHP_SELF']),
		],

	);
<file_sep>/app/frontend/controllers/SiteController.php
<?php

	namespace frontend\controllers;

	use deepkit\core\Controller;
	use frontend\models\SiteModel;

	/**
	* Main start point of app
	*/
	class SiteController extends Controller {

		protected function index() {

			/**
			* Generate action view page template
			*
			* arg[0] -> model data
			* arg[1] -> full view
			*/
			$this->generateView(
				(new SiteModel)->index(...$this->data),
				true
			);
		}

	}
<file_sep>/setup/Generator.php
<?php

	namespace setup;

	use deepkit\helpers\DataFilter;
	use deepkit\core\PluginManager;

	/**
	* DeepKit module generator class
	*/
	class Generator {

		/**
		 * folders - relative paths array for create new files
		 *
		 * @var mixed
		 */
		private $folders = [
			'plugins' 	=> PATH.'/plugins',
			'modules' 	=> PATH.'/app',
			'widgets' 	=> PATH.'/app/common/widgets',
		];

		/**
		 * system_folders - list of all directories for init app project
		 *
		 * @var mixed
		 */
		private $system_folders = [
			'app',

		];

		/**
		 * migrations - list of database migration files (included plugins)
		 *
		 * @var mixed
		 */
		public $migrations = [];

		/**
		 * plugins - list of active (installed) plugins
		 *
		 * (default value: [])
		 *
		 * @var mixed
		 */
		public $plugins = [];

		/**
		 * __construct function
		 *
		 * @return void
		 */
		function __construct() {
			// set up folders for scan migrations
			$directories = [
				PATH.'/system/database/migrations',
				PATH.'/plugins',
			];

			// start scan
			foreach ($directories as $dir) {
				$this->register_migrations($dir);
			}

			// get active plugins
			$this->plugins = (new PluginManager)->plugins;
		}

		/**
		 * Register migrations function for build array with all migration files
		 *
		 * @return void
		 */
		private function register_migrations($folder) {
			// remove unused folders and hidden files
			$files_list = array_diff(scandir($folder), ['.', '..', '.DS_Store']);
			// scan each folder files
			foreach ($files_list as $file) {
				// build full file path
				$file_path = realpath($folder.'/'.$file);

				// if filename startswith 'migration.'
				if (preg_match("/^migration.*/", $file) && is_file($file_path)) {
					// append to array
					$this->migrations[$file] = $file_path;
				} else if (is_dir($file_path)) {
					// if it's a directory -> recursive scan files
					$this->register_migrations($file_path);
				}
			}
		}

		/**
		 * init_app function for create system project folders
		 *
		 * @return void
		 */
		public function init_app() {
			// scan each folder existing
			foreach ($this->system_folders as $dir) {
				// if not -> create it
				if (!is_dir($dir)) mkdir($dir, 0644);
			}
		}

		/**
		 * Create module function for create all needed files and folders for new module
		 *
		 * @param mixed $post
		 * $name - module name
		 * $description - short description for code comments
		 * $side - application side (front | back) end
		 * $have_controller - create controller or not
		 * $have_model - create model or not
		 * $table_name - MySQL table name
		 * $actions - controller actions (views)
		 * @return void
		 */
		public function create_module($post) {
			// process module information data
			$name = ucfirst(strtolower(DataFilter::SecureStrings($post['module_name'])));
			$description = DataFilter::Strings($post['description']);
			$side = DataFilter::Integers($post['side']);
			$have_controller = isset($post['have_controller']) ? true : false;
			$have_model = isset($post['have_model']) ? true : false;
			$table_name = strtolower($post['table_name']);
			$actions = explode(',', $post['actions']);

			$plugin = isset($post['plugin']) ? $post['plugin'] : null;

			// select side folder name by index
			switch ($side) {
				case 0:
					$side = 'frontend';
					break;
				case 1:
					$side = 'backend';
					break;
				default:
					$side = 'common';
					break;
			}

			// build full path to module place and templates folder
			if (!is_null($plugin)) {
				// if it's a plugin -> change path
				$module_directory = realpath(
					$this->folders['plugins']."/{$plugin}/{$side}"
				);

				$views_directory = $this->folders['plugins']."/{$plugin}/views/{$side}/".strtolower($name);
			} else {
				$module_directory = realpath(
					$this->folders['modules']."/{$side}"
				);

				$views_directory = $this->folders['modules']."/{$side}/views/".strtolower($name);
			}

			// build file paths
			$files = [
				"controller" => "{$module_directory}/controllers/{$name}Controller.php",
				"model" => "{$module_directory}/models/{$name}Model.php"
			];

			// create if not exists templates folder
			if (!is_dir($views_directory) && $have_controller) mkdir($views_directory, 0777);

			// create actions array
			$actions_content = [
				'controller' => [],
				'model' => []
			];

			// namespace template (for plugin modules)
			$plugin_namespace = (!is_null($plugin)) ? "plugins\\".strtolower($plugin)."\\" : '' ;

			// if haven't local model -> set common namespace
			$model_side = (!$have_model) ? 'common' : $side;

			// controller and model content pre-template
			$controller_content = "<?php

	namespace {$plugin_namespace}{$side}\controllers;

	use deepkit\core\Controller;
	use {$plugin_namespace}{$model_side}\models\\".$name."Model;

	/**
	* {$description}
	*/
	class {$name}Controller extends Controller {

		***actions***

	}
";
			$model_content = "<?php

	namespace {$plugin_namespace}{$side}\models;

	use deepkit\core\Model;

	use deepkit\helpers\CookieHelper;
	use deepkit\helpers\DataFilter;
	use deepkit\helpers\DebugHelper;
	use deepkit\helpers\ErrorHelper;
	use deepkit\helpers\NotifyHelper;
	use deepkit\helpers\FormHelper;

	/**
	* {$description}
	*/
	class {$name}Model extends Model {

		/**
		 * @inheritDoc
		 */
		protected \$table_name = '{$table_name}';

		***actions***

	}
";

			// generate actions content
			foreach ($actions as $x) {
				// create template file with content
				if ($have_controller) file_put_contents($views_directory."/{$x}.html", strtolower($name)."/{$x}"); // module/action

				// append to actions arrays
				array_push($actions_content['controller'], "protected function {$x}() {

			/**
			* Generate action view page template
			*
			* arg[0] -> model data
			* arg[1] -> full view
			*/
			\$this->generateView(
				(new {$name}Model)->{$x}(...\$this->data),
				true
			);
		}");

				array_push($actions_content['model'], "/**
		* ".ucfirst($x)."
		*
		* {$x} action of controller
		*/
		public function {$x}(\$args = null) {
			\$data = [];

			// template view result
			return \$data;
		}");
			}

			// build controller and model contents
			$controller_content = str_replace("***actions***", implode("\n\n\t\t", $actions_content['controller']), $controller_content);
			$model_content = str_replace("***actions***", implode("\n\n\t\t", $actions_content['model']), $model_content);

			// create files if needed
			if ($have_controller) file_put_contents($files['controller'], $controller_content);
			if ($have_model) file_put_contents($files['model'], $model_content);
		}

		/**
		 * Create widget function
		 *
		 * @access public
		 * @param mixed $name - title of widget files
		 * @param mixed $description - short description for code comments
		 * @return void
		 */
		public function create_widget($post) {
			// filter widget information
			$name = ucfirst(strtolower(DataFilter::SecureStrings($post['widget_name'])));
			$description = DataFilter::Strings($post['description']);

			// set up folders path and file
			$templates_directory = $this->folders['widgets']."/".strtolower($name);

			$template_file = $templates_directory."/view.html";
			$widget_class = $templates_directory."/{$name}Widget.php";

			// create widget file
			$widget_content = "<?php

	namespace common\widgets\\".strtolower($name).";

	use deepkit\core\Widget;

	/**
	* {$description}
	*/
	class {$name}Widget extends Widget {

		protected \$template = '".strtolower($name)."';

		protected function data() {

			\$data['string'] = 'Hello World!';

			return \$data;
		}

	}
";
			// create widget HTML template
            if (!is_dir($templates_directory))
			    mkdir($templates_directory, 0777);

            file_put_contents($widget_class, $widget_content);
			file_put_contents($template_file, "{{ string }}");
		}

		public function execute_migration($post) {
			// check file exists
			if (!file_exists($post['migration'])) return;

			// include migration file (autoexec)
			include($post['migration']);
		}

		public function create_plugin($post) {
			// filter plugin info
			$name = DataFilter::SecureStrings($post['name']);
			$frontend = isset($post['frontend']) ? true : false;
			$backend = isset($post['backend']) ? true : false;
			$common = isset($post['common']) ? true : false;

			// set up base directories for create
			$directories = [
				"{$name}",
				"{$name}/migration"
			];

			if ($frontend) {
				array_push($directories, "{$name}/frontend");
				array_push($directories, "{$name}/frontend/controllers");
				array_push($directories, "{$name}/frontend/models");
				array_push($directories, "{$name}/frontend/views");
			}
			if ($backend) {
				array_push($directories, "{$name}/backend");
				array_push($directories, "{$name}/backend/controllers");
				array_push($directories, "{$name}/backend/models");
				array_push($directories, "{$name}/backend/views");
			}
			if ($common) {
				array_push($directories, "{$name}/common");
				array_push($directories, "{$name}/common/models");
			}

			// create each directory
			foreach ($directories as $dir) {
				$dir = $this->folders['plugins']."/{$dir}";
				if (!is_dir($dir)) mkdir($dir, 0777);
			}

			// migration file
			$migration_content = "<?php

	use deepkit\core\Migrator;

	// create new migration object
	\$migrator = new Migrator();

	// drop tables
	// create tables
	// create realations
	// insert base content";

			// plugin config file
			$config_content = "<?php

	return [
		'enabled' => true,

		'rules' => [
			'frontend' => [
				//'controller/*' => 'controller/action/$1',
			],

			'backend' => [
				//'controller/*' => 'controller/action/$1',
			]
		],
	];";

			// write content to files
			file_put_contents($this->folders['plugins']."/{$name}/migration/migration.{$name}.php", $migration_content);
			file_put_contents($this->folders['plugins']."/{$name}/config.php", $config_content);
		}

		public function install_plugin ($zip) {
			// code
		}

	}
<file_sep>/app/common/models/ConfigModel.php
<?php

	namespace common\models;

	use deepkit\core\Model;

	use deepkit\helpers\CookieHelper;
	use deepkit\helpers\DataFilter;
	use deepkit\helpers\DebugHelper;
	use deepkit\helpers\ErrorHelper;
	use deepkit\helpers\NotifyHelper;
	use deepkit\helpers\FormHelper;

	/**
	* App configurations manager module
	*/
	class ConfigModel extends Model {

		/**
		* Table name
		*
		* Override class property 'table_name'
		*/
		protected $table_name = 'system_config';

		/**
		* Index
		*
		* index action of controller
		*/
		public function index($args = null) {
			$data = [];

			// template view result
			return $data;
		}

		/**
		* Edit
		*
		* edit action of controller
		*/
		public function edit($args = null) {
			$data = [];

			// template view result
			return $data;
		}

		/**
		* Load
		*
		* load action of controller
		*/
		public function load($args = null) {
			$data = [];

			// template view result
			return $data;
		}

		/**
		* Update
		*
		* update action of controller
		*/
		public function update($args = null) {
			$data = [];

			// template view result
			return $data;
		}

		/**
		* Delete
		*
		* delete action of controller
		*/
		public function delete($args = null) {
			$data = [];

			// template view result
			return $data;
		}

	}
<file_sep>/system/deepkit/helpers/DataFilter.php
<?php

	namespace deepkit\helpers;

	use system\App;

	/**
	* Module for clear strings, formatting values and filter variables
	*/
	class DataFilter {

		/**
		* Clear INTEGER
		*
		* Replace characters for get clear integer number
		*
		* @param string $string -> data for reformat
		*/
		public static function Integers($string) {

			// replace non 0-9 characters
			$out = preg_replace("/[^0-9]+/", "", $string);

			// convert to integer
			$out = intval($out);

			// return clear value
			return $out;
		}

		/**
		* Clear number (float, decimal)
		*
		* Replace characters for get clear number with comma or dot
		*
		* @param string $string -> data for reformat
		*/
		public static function Numbers($string) {

			// replace non 0-9., characters
			$out = preg_replace("/[^0-9.,]+/", "", $string);

			// convert to float value
			$out = floatval($out);

			// return clear value
			return $out;
		}

		/**
		* Clear boolean
		*
		* Get boolean value for requested string
		*
		* @param string $string -> data for reformat
		*/
		public static function Bools($string) {

			// check value is not empty
			if (!isset($string) || is_null($string)) return false;

			// remove spaces
			$out = trim($string);

			// check text values same as boolean
			$out = (strtolower($out) == 'false') ? '0' : $out;

			// convert to bool value
			$out = (boolval($out)) ? true : false;

			// return clear value
			return $out;
		}

		/**
		* Clear simple string
		*
		* Remove danger characters from string value (firstname, product name, category, etc)
		*
		* @param string $string -> data for reformat
		*/
		public static function Strings($string) {

			// remove spaces
			$out = trim($string);

			// remove danger characters
			$out = preg_replace("/[^-_0-9a-zA-Zа-яА-Я(),.\s#]+/u", "", $out);

			// return clear value
			return $out;
		}

		/**
		* Clear secure string (word)
		*
		* Remove danger characters from string value (login, password, filename, etc)
		*
		* @param string $string -> data for reformat
		*/
		public static function SecureStrings($string) {

			// remove spaces
			$out = trim($string);

			// remove danger characters
			$out = preg_replace("/[^_0-9a-zA-Zа-яА-Я]+/u", "", $out);

			// return clear value
			return $out;
		}

		/**
		* Clear URL address string
		*
		* Remove denied characters from URL string for security reasons
		*
		* @param string $string -> data for reformat
		*/
		public static function Url($string) {

			// remove spaces
			$out = trim($string);

			// decode from URL into string value
			$out = urldecode($out);

			// remove denied characters
			$out = preg_replace("/[^-_0-9a-zA-Z=&\/.]+/u", "", $out);

			// return clear value
			return $out;
		}

		/**
		* Clear E-Mail address
		*
		* Remove denied characters from E-Mail for security reasons
		*
		* @param string $string -> data for reformat
		*/
		public static function Email($string) {

			// remove spaces
			$out = trim($string);

			// remove denied characters
			$out = preg_replace("/[^-_0-9a-zA-Z.@]+/", "", $out);

			// return clear value
			return $out;
		}

		/**
		* HTML Encode
		*
		* Convert HTML code into secure text string
		*
		* @param string $string -> data for reformat
		*/
		public static function HtmlEncode($string) {

			// remove spaces
			$out = trim($string);

			// convert to special characters
			$out = htmlspecialchars($out);

			// return clear value
			return $out;
		}

		/**
		* HTML Remove
		*
		* Remove all tags from HTML code
		*
		* @param string $string -> data for reformat
		*/
		public static function HtmlRemove($string) {

			// remove spaces
			$out = trim($string);

			// remove HTML tags
			$out = strip_tags($out);

			// return clear value
			return $out;
		}

		/**
		* HTML Decode
		*
		* Convert text string into HTML code
		*
		* @param string $string -> data for reformat
		*/
		public static function HtmlDecode($string) {

			// convert from special characters
			$out = htmlspecialchars_decode($string);

			// return clear value
			return $out;
		}

		/**
		* Dump object info
		*
		* Show 'var_dump' result as JSON pretty print
		*
		* @param object $object -> object for dumping
		* @param bool $return_as_text -> choose echo or string returns
		*/
		public static function Dump($object, $return_as_text = false) {

			// create start-end strings
			$start 	= "
";
			$end 	= "
";

			// convert object into JSON format
			$out = json_encode($object, JSON_PRETTY_PRINT);

			// concate result string
			$out = $start.$out.$end;

			// if mustn't return as text
			if (!$return_as_text) {

				// print result on page
				echo $out;
			} else {

				// return result
				return $out;
			}
		}

		/**
		* Get Hash
		*
		* Return HASH for some string value with SALT key
		*
		* @param string $string -> data for hashing
		*/
		public static function GetHash($string) {

			// generate hash
			$out = hash(
				App::$config->security->hash_type,
				(App::$config->security->salt . $string . App::$config->security->salt),
				true //for binary 32 bit encoding
			);

			// return clear value
			return $out;
		}

	}
<file_sep>/app/backend/controllers/MenuController.php
<?php

	namespace backend\controllers;

	use deepkit\core\Controller;
	use common\models\MenuModel;

	/**
	* Main system menu module
	*/
	class MenuController extends Controller {

		protected function index() {

			/**
			* Generate action view page template
			*
			* arg[0] -> model data
			* arg[1] -> full view
			*/
			$this->generateView(
				(new MenuModel)->index(...$this->data),
				true
			);
		}

		protected function edit() {

			/**
			* Generate action view page template
			*
			* arg[0] -> model data
			* arg[1] -> full view
			*/
			$this->generateView(
				(new MenuModel)->edit(...$this->data),
				true
			);
		}

	}
<file_sep>/system/database/migrations/migration.base.php
<?php

	use deepkit\core\Migrator;
	use deepkit\helpers\DataFilter;

	// create new migration object
	$migrator = new Migrator();

	// drop tables
	$migrator->dropTable('system_config');
	$migrator->dropTable('system_user_role');
	$migrator->dropTable('system_user');
	$migrator->dropTable('system_menu');
	$migrator->dropTable('system_meta');
	$migrator->dropTable('system_page');
	$migrator->dropTable('system_widget');
	$migrator->dropTable('system_comments');
	$migrator->dropTable('system_subscriptions');

	// config table
	$migrator->createTable('system_config', 'id', [
		'id' 	=> 'int(10) unsigned not null auto_increment',
		'name' 	=> 'varchar(255) not null',
		'value' => 'mediumtext null'
	]);
	$migrator->setUniqueIndex('system_config', 'name');

	// user role table
	$migrator->createTable('system_user_role', 'id', [
		'id' 			=> 'int(10) unsigned not null auto_increment',
		'name' 			=> 'varchar(255) not null',
		'alias' 		=> 'varchar(255) not null',
		'permissions' 	=> 'mediumtext null'
	]);
	$migrator->setUniqueIndex('system_user_role', 'name');

	// user table
	$migrator->createTable('system_user', 'id', [
		'id' 				=> 'int(10) unsigned not null auto_increment',
		'username' 			=> 'varchar(255) not null',
		'password' 			=> '<PASSWORD>(<PASSWORD>',
		'email' 			=> 'varchar(255) not null',
		'name' 				=> 'varchar(255) null',
		'status' 			=> 'tinyint(1) not null default 0',
		'registered_date' 	=> 'timestamp not null default current_timestamp',
		'login_date' 		=> 'timestamp null',
		'token' 			=> 'varchar(255) null',
		'roles' 			=> 'varchar(255) null',
		'data' 				=> 'mediumtext null comment "json"'
	]);
	$migrator->setUniqueIndex('system_user', 'username');
	$migrator->setUniqueIndex('system_user', 'email');

	// menu table
	$migrator->createTable('system_menu', 'id', [
		'id' 		=> 'int(10) unsigned not null auto_increment',
		'parent_id' => 'int(10) unsigned not null default 0',
		'priority' 	=> 'int(10) unsigned not null default 1',
		'status' 	=> 'tinyint(1) not null default 0',
		'title' 	=> 'varchar(255) not null',
		'link' 		=> 'varchar(255) not null default "/"',
		'roles' 	=> 'varchar(255) null',
		'data' 		=> 'mediumtext null comment "json"'
	]);

	// pages table
	$migrator->createTable('system_page', 'id', [
		'id' 		=> 'int(10) unsigned not null auto_increment',
		'title' 	=> 'varchar(255) not null',
		'alias' 	=> 'varchar(255) not null',
		'content' 	=> 'longtext null',
		'image' 	=> 'varchar(255) null',
		'status' 	=> 'int(1) not null default 0',
		'data'		=> 'mediumtext null comment "json"'
	]);

	// meta table
	$migrator->createTable('system_meta', 'id', [
		'id' 			=> 'int(10) unsigned not null auto_increment',
		'title' 		=> 'varchar(255) null',
		'description' 	=> 'varchar(255) null',
		'keywords' 		=> 'varchar(255) null',
		'author' 		=> 'varchar(255) null',
		'page' 			=> 'int(10) unsigned not null'
	]);
	$migrator->createRelation([
		'system_meta' => 'page',
		'system_page' => 'id'
	]);

	// widgets table
	$migrator->createTable('system_widget', 'id', [
		'id' 		=> 'int(10) unsigned not null auto_increment',
		'name' 		=> 'varchar(255) not null',
		'status' 	=> 'tinyint(1) not null default 0',
		'pages' 	=> 'varchar(255) null',
		'content' 	=> 'mediumtext null',
		'roles' 	=> 'varchar(255) null',
		'priority' 	=> 'int(10) not null default 0',
		'position' 	=> 'varchar(255) null',
		'data' 		=> 'mediumtext null comment "json"'
	]);

	// comments table
	$migrator->createTable('system_comments', 'id', [
		'id' 			=> 'int(10) not null',
		'parent_id' 	=> 'int(10) not null default 0',
		'user' 			=> 'varchar(255) not null',
		'status' 		=> 'tinyint(1) not null default 0',
		'created_date' 	=> 'timestamp not null default current_timestamp',
		'edited_date' 	=> 'timestamp null',
		'content' 		=> 'tinytext null'
	]);

	// subscribes tables
	$migrator->createTable('system_subscriptions', 'id', [
		'id' 			=> 'int(10) unsigned not null auto_increment',
		'status' 		=> 'tinyint(1) not null default 0',
		'title' 		=> 'varchar(255) not null',
		'description' 	=> 'varchar(255) null',
		'users' 		=> 'mediumtext null',
		'data' 			=> 'mediumtext null comment "json"'
	]);
<file_sep>/system/config/namespaces.php
<?php

	// Namespace => Path

	return array(

		// APP SECTION

		'common'	=> 'app\common',

		'backend'	=> 'app\backend',

		'frontend'	=> 'app\frontend',

		// 	SYSTEM SECTION

		'deepkit' 	=> 'system\deepkit',

		'vendor' 	=> 'system\vendor',

		// VENDOR SECTION

		# Twig templater source path
		'Twig'		=> 'system\vendor\Twig',

	);<file_sep>/app/common/widgets/menu/MenuWidget.php
<?php

	namespace common\widgets\menu;

	use deepkit\core\Widget;

	/**
	* Main website menu widget
	*/
	class MenuWidget extends Widget {

		protected $template = 'menu';

		protected function data() {

			$data['meta'] = [
			    'logo' => 'assets/img/logo-inverse.png',
                'site_name' => 'DeepKit'
            ];

			return $data;
		}

	}
<file_sep>/system/deepkit/helpers/ErrorHelper.php
<?php

	namespace deepkit\helpers;

	// include some classes
	use system\App;

	/**
	* Class for show error pages and exceptions
	*/
	class ErrorHelper {

		/**
		* Show Error Page
		*
		* Function for show error page with variable message
		*
		* @param string $error_code
		* @param string $message -> error content
		*/
		public static function showError($error_code, $message = 'Error') {

			// generate full path to page template
			$page_template = "templates/error.html";

			// display error page
			echo App::$twig->render($page_template, array(
				'code' 	=> $error_code,
				'text' 	=> $message,
				'lang'	=> App::$meta['language']
			));

			// kill app after error shown
			die();
		}

	}
<file_sep>/setup/index.php
<?php

// include class autoloader
include(
realpath(__DIR__ . '/../system/autoload.php')
);

use system\App;
use setup\Generator;

use deepkit\helpers\ErrorHelper;
use deepkit\helpers\FormHelper;

$app = new App;
$app->Start($routing = false);

if (!App::$config->generator->enabled) {
    ErrorHelper::showError('403', 'Access denied!');
}

$generator = new Generator();

if (isset($_POST['action'])) {
    FormHelper::CSRF_check($_POST);

    $action = isset($_POST['mode']) ? strtolower($_POST['mode']) : false;

    switch ($action) {
        case 'module';
            $generator->create_module($_POST);
            break;
        case 'widget';
            $generator->create_widget($_POST);
            break;
        case 'migration';
            $generator->execute_migration($_POST);
            break;
        case 'create_plugin';
            $generator->create_plugin($_POST);
            break;
        case 'create_plugin_module':
            $generator->create_module($_POST);
            break;
        case 'install_plugin';
            //code
            break;
    }
}

?>
<!doctype html>

    <meta charset="utf-8">
    <title>Deepkit Generator</title>

    <link rel="stylesheet" href="/setup/assets/generator.css">

Deepkit Generator

Module

Widget

Database Migration

Create plugin

Create plugin module

Install plugin

                    <form method="POST">
                        <input type="hidden" name="mode" value="module">

                                <input name="module_name" type="text" class="validate" autocomplete="off"
                                       title="Module name" required>
                                Module name

                                <input name="table_name" type="text" class="validate" autocomplete="off"
                                       title="Database Table name" required>
                                Database table name

                                <textarea name="description" class="materialize-textarea"
                                          placeholder="Module short description"></textarea>
                                Description

                                <select name="side" title="Application side select" required>
                                    <option value="" disabled selected>Choose side option</option>
                                    <option value="0">Front-end</option>
                                    <option value="1">Back-end</option>
                                    <option value="2">Common</option>
                                </select>
                                App side

                                <input name="actions" type="text" class="validate" autocomplete="off"
                                       title="Module controller actions" required>

                                    Actions (separate by ',')

                                <input type="checkbox" name="have_controller" id="controller" checked/>
                                Generate controller (views)

                                <input type="checkbox" name="have_model" id="model" checked/>
                                Generate model

                                <button class="btn btn-large waves-effect waves-light" type="submit" name="action">
                                    Generate
                                    send
                                </button>

                    </form>

                    <form method="post">
                        <input type="hidden" name="mode" value="widget">

                                <input name="widget_name" type="text" class="validate" autocomplete="off"
                                       title="Widget name" required>
                                Widget name

                                <textarea name="description" class="materialize-textarea"
                                          title="Widget short description" required></textarea>
                                Description

                                <button class="btn btn-large waves-effect waves-light" type="submit" name="action">
                                    Generate
                                    send
                                </button>

                    </form>

                    <form method="post">
                        <input type="hidden" name="mode" value="migration">

                                <select name="migration" title="Migration object select" required>
                                    <option value="" disabled selected>Choose migration</option>
                                    <?php foreach ($generator->migrations as $file => $path) : ?>
                                        <option value="<?= $path ?>"><?= $file ?></option>
                                    <?php endforeach ?>
                                </select>
                                Migration to execte

                                <button class="btn btn-large waves-effect waves-light" type="submit" name="action">
                                    Execute
                                    send
                                </button>

                    </form>

                    <form method="post">
                        <input type="hidden" name="mode" value="create_plugin">

                                <input name="name" type="text" class="validate" autocomplete="off" title="Plugin name"
                                       required>
                                Plugin name

                                    <input type="checkbox" name="frontend" id="frontend" checked/>
                                    Frontend

                                    <input type="checkbox" name="backend" id="backend" checked/>
                                    Backend

                                    <input type="checkbox" name="common" id="common" checked/>
                                    Common

                                <button class="btn btn-large waves-effect waves-light" type="submit" name="action">
                                    Generate
                                    send
                                </button>

                    </form>

                    <form method="post">
                        <input type="hidden" name="mode" value="create_plugin_module">

                                <select name="plugin" title="Plugin object select">
                                    <option value="" disabled selected>Choose plugin</option>
                                    <?php foreach ($generator->plugins as $name => $content) : ?>
                                        <option value="<?= $name ?>"><?= $name ?></option>
                                    <?php endforeach ?>
                                </select>
                                Select plugin

                                <input name="module_name" type="text" class="validate" autocomplete="off"
                                       title="Module name" required>
                                Module name

                                <input name="table_name" type="text" class="validate" autocomplete="off"
                                       title="Database Table name" required>
                                Database table name

                                <textarea name="description" class="materialize-textarea"
                                          title="Module short description" required></textarea>
                                Description

                                <select name="side" title="Application side select" required>
                                    <option value="" disabled selected>Choose side option</option>
                                    <option value="0">Front-end</option>
                                    <option value="1">Back-end</option>
                                    <option value="2">Common</option>
                                </select>
                                App side

                                <input name="actions" type="text" class="validate" autocomplete="off"
                                       title="Module controller actions" required>

                                    Actions (separate by ',')

                                <input type="checkbox" name="have_controller" id="controller" checked/>
                                Generate controller (views)

                                <input type="checkbox" name="have_model" id="model" checked/>
                                Generate model

                                <button class="btn btn-large waves-effect waves-light" type="submit" name="action">
                                    Generate
                                    send
                                </button>

                    </form>

Work in progress...

<file_sep>/system/deepkit/core/Controller.php
<?php

	namespace deepkit\core;

	use system\App;
	use deepkit\helpers\ErrorHelper;
	use deepkit\helpers\DebugHelper;

	/**
	* Controller main class
	*/
	class Controller {

		/**
		* Data
		*
		* @var string $data -> $_GET args from request
		*/
		protected $data;

		/**
		* Action
		*
		* @var string $action -> Action name for execute
		*/
		protected $action;

		/**
		 * Main class init function
		 * @param string $action_name  Controller action name
		 * @param string $request_data Request data string
		 */
		public function __construct($action_name, $request_data) {

			// set action name
			$this->action = $action_name;

			// set $_GET data
			$this->data = $request_data;
		}

		/**
		* Execute action
		*
		* Execute controller action for process model data
		*/
		public function executeAction() {

			// return new action
			return $this->{$this->action}();
		}

		/**
		 * Print HTML template with Twig object with model data
		 * @param  object $model -> Model object
		 * @param  bool $full_view -> Generate HTML view for main site or only action
		 *
		 */
		public function generateView($model = null, $full_view = true) {

			// if request is AJAX - return data only
			if (Router::isAjax()) {
				echo json_encode($model);
				return;
			}

			// get full class name
			$class_name = get_class($this);

			// check application side (frontend | backend)
			$app_side = (preg_match("[^backend]", $class_name)) ? 'backend' : 'frontend' ;

			// remove unused parts of class name (in lowercase)
			$controller_name = strtolower(
				preg_replace("/([\a-zA-Z])+controllers\\\([\\a-zA-Z]+)Controller/", "$2", $class_name)
			);

			// build path to web page template
			$template = "{$app_side}/views/{$controller_name}/{$this->action}.html";

			// if some plugin is active -> append to path
			$template = (!is_null(App::$active_plugin)) ? App::$active_plugin.'/'.$template : $template;

			// build path to main template
			$main_template = "{$app_side}/views/main.html";

			// print render template
			if (file_exists(PATH . "/app/" . $main_template)) {

				// get render action template only
				if (file_exists(PATH . '/app/' . $template) || file_exists(PATH . '/plugins/' . $template) ) {

					// action page template render with model data
					$action_template = App::$twig->render(
						$template,
						// if model equals NULL return empty array
						(is_null($model)) ? [] : $model
					);
				} else {

					// show error page
					ErrorHelper::showError('404', 'Page template not found');
				}

				if ($full_view) {

					// print full page with template render
					echo App::$twig->render(
						$main_template, [
							'meta'			=> App::$meta,
							'template' 		=> $action_template,
							'debug_toolbar' => DebugHelper::Render(),
						]
					);
				} else {

					// print single template
					echo $action_template;
				}

			} else {

				// show error page
				ErrorHelper::showError('404', 'Main template not found');
			}
		}

	}
<file_sep>/app/backend/models/PluginModel.php
<?php

	namespace backend\models;

	use deepkit\core\Model;

	use deepkit\helpers\CookieHelper;
	use deepkit\helpers\DataFilter;
	use deepkit\helpers\DebugHelper;
	use deepkit\helpers\ErrorHelper;
	use deepkit\helpers\NotifyHelper;
	use deepkit\helpers\FormHelper;

	/**
	* System plugins manager module
	*/
	class PluginModel extends Model {

		/**
		* Table name
		*
		* Override class property 'table_name'
		*/
		protected $table_name = 'system_plugins';

		/**
		* Index
		*
		* index action of controller
		*/
		public function index($args = null) {
			$data = [];

			// template view result
			return $data;
		}

        /**
         * Edit
         *
         * edit action of controller
         */
        public function edit($args = null) {
            $data = [];

            // template view result
            return $data;
        }

        /**
         * Upload
         *
         * upload action of controller
         */
        public function upload($args = null) {
            $data = [];

            // template view result
            return $data;
        }

	}
<file_sep>/system/deepkit/core/Migrator.php
<?php

	namespace deepkit\core;

	use deepkit\core\Database;
	use deepkit\helpers\ErrorHelper;
	use depekit\helpers\NotifyHelper;

	/**
	* Class for manage MySQL database migrations
	*/
	class Migrator extends Database {

		/**
		* Create table
		*
		* Function for create new table
		*
		*	Example:
		*
		*	$table_name = 'users';
		*	$primary_key = 'id';
		*	$columns = [
		*		'id' 		=> 'int not null auto_increment',
		*		'login' 	=> 'varchar(45) not null',
		*		'password'	=> 'varchar(255) not null',
		*	];
		*
		* @param string $table_name
		* @param string $primary_key
		* @param array $columns
		*/
		public function createTable($table_name, $primary_key, $columns) {

			// prepare table SQL command string
			$sql_string = "create table if not exists `{$table_name}` (";

			// append columns SQL
			foreach ($columns as $name => $props) {
				$sql_string .= "`{$name}` {$props},";
			}

			// append primary key SQL
			$sql_string .= "primary key (`{$primary_key}`) )";

			// prepare query
			$this->query($sql_string);

			// return execute result
			return $this->execute();
		}

		/**
		 * Set up UNIQUE index for table.
		 *
		 * @param mixed $table_name
		 * @param mixed $column
		 * @return void
		 */
		public function setUniqueIndex($table_name, $column) {

			// prepare SQL command
			$sql_string = "
				ALTER TABLE `{$table_name}`
				ADD UNIQUE INDEX `{$column}_UNIQUE` (`{$column}` ASC);
			";

			// prepare query
			$this->query($sql_string);

			// return execute result
			return $this->execute();

		}

		/**
		* Create relation
		*
		* Function for create foreign key
		*
		*	Example:
		*
		*	-- Many 'posts' to one 'user' --
		*
		*	$relation = [
		*		'posts' => 'author_id',
		*		'users' => 'id'
		*	];
		*
		* @param array $relation
		*/
		public function createRelation($relation) {

			// get tables from query string
			$tables = array_keys($relation);

			// get columns from query string
			$columns = array_values($relation);

			// prepare SQL string
			$sql_string = "
				ALTER TABLE `{$tables[0]}`
				ADD INDEX `fk_{$columns[0]}_idx` (`{$columns[0]}` ASC);

				ALTER TABLE `{$tables[0]}`
				ADD CONSTRAINT `fk_{$columns[0]}`
				  FOREIGN KEY (`{$columns[0]}`)
				  REFERENCES `{$tables[1]}` (`{$columns[1]}`)
				  ON DELETE NO ACTION
				  ON UPDATE NO ACTION;
			";

			// prepare query
			$this->query($sql_string);

			// return execute result
			return $this->execute();
		}

		/**
		* Drop table
		*
		* Function for drop table by name
		* @param string $table_name
		*/
		public function dropTable($table_name) {

			// prepare SQL string
			$sql_string = "drop table if exists `{$table_name}`";

			// prepare query
			$this->query($sql_string);

			// return execute result
			return $this->execute();
		}

		/**
		* Execute all
		*
		* Function for multiple execute queries
		*
		*	Example:
		*
		*	$queries_array = [
		*		"insert into `user` (`login`,`password`) values ('<PASSWORD>','<PASSWORD>')",
		*		"insert into `user` (`login`,`password`) values ('<PASSWORD>','<PASSWORD>')",
		*	];
		*
		* @param array $queries_array
		*/
		public function executeAll($queries_array) {

			// execute each query
			foreach ($queries_array as $query) {

				// prepare
				$this->query($query);

				// execute
				$this->execute();
			}
		}

		/**
		* Reset increment
		*
		* Function for reset Auto_Increment table counter
		*
		* @param string $table_name [description]
		*/
		public function resetIncrement($table_name) {

			// prepare SQL string
			$sql_string = "alter table `{$table_name}` auto_increment = 1";

			// prepare query
			$this->query($sql_string);

			// return execute result
			return $this->execute();
		}

	}
<file_sep>/system/deepkit/helpers/NotifyHelper.php
<?php

	namespace deepkit\helpers;

	/**
	* Class for showing some alerts and notifications on page
	*/
	class NotifyHelper {

		/**
		* Set text
		*
		* Setting up message for session notify
		*
		* @param string $text
		* @param string $type
		*/
		public static function setText($text, $type = 'danger') {

			// create new message array
			$message = [
				'text' => $text,
				'type' => $type
			];

			// check session storage exists
			if (isset($_SESSION['notify'])) {

				// insert new value into array
				array_push($_SESSION['notify'], $message);
			} else {

				// insert new array into session
				$_SESSION['notify'] = [
					$message,
				];
			}
		}

		/**
		* Show text
		*
		* Print message with specififc HTML markup
		*/
		public static function showText() {

			// check message storage exists
			if (isset($_SESSION['notify'])) {

				// create empty output string
				$output = '';

				// start generate HTML for messages
				foreach ($_SESSION['notify'] as $message) {

					// create alert block
					$alert_html = "

{$message['text']}

					";

					// append new block to output string
					$output .= $alert_html;
				}

				// reset session storage
				unset($_SESSION['notify']);

				// print result on web page
				echo $output;
			}
		}

		/**
		 * Function for automatic set up NotifyFilter message
		 *
		 * @param object $queryObject -> executed query object
		 */
		public static function setResultNotify($queryObject) {
			if ($queryObject) {
				NotifyHelper::setText('All changes was saved!', 'success');
			} else {
				NotifyHelper::setText('Database query error');
			}
		}

		/**
		 * Return message for AJAX request
		 *
		 * @param  object $queryObject
		 * @return array $message
		 */
		public static function ajaxMessage($queryObject) {
			$message = [];

			if ($queryObject) {
				$message = [
					'content' 	=> 'All changes was saved!',
					'type' 		=> 'success',
					'icon'		=> 'check'
				];
			} else {
				$message = [
					'content' 	=> 'Saving error!',
					'type' 		=> 'danger',
					'icon'		=> 'ban'
				];
			}

			return $message;
		}

	}
<file_sep>/index.php
<?php

	// include class autoloader
	require_once(__DIR__.'/system/autoload.php');

	// connect main app bootloader
	use system\App;

	// create main app object
	$app = new App;

	// start application
	$app->Start();
<file_sep>/app/frontend/models/PageModel.php
<?php

	namespace frontend\models;

	use deepkit\core\Model;

	use deepkit\helpers\CookieHelper;
	use deepkit\helpers\DataFilter;
	use deepkit\helpers\DebugHelper;
	use deepkit\helpers\ErrorHelper;
	use deepkit\helpers\NotifyHelper;
	use deepkit\helpers\FormHelper;

	/**
	* Main page items module
	*/
	class PageModel extends Model {

		/**
		* Table name
		*
		* Override class property 'table_name'
		*/
		protected $table_name = 'system_page';

		/**
		* Index
		*
		* index action of controller
		*/
		public function index($args = null) {
			$data = [];

			// template view result
			return $data;
		}

		/**
		* View
		*
		* view action of controller
		*/
		public function view($args = null) {
			$data = [];

			// template view result
			return $data;
		}

	}
<file_sep>/assets/js/backend.js
function formDeleteConfirmation () {
    // delete button confirmation
    $('#delete').on('click', function (e) {
        e.preventDefault();
        $(this).blur();
        // show confirm dialog
        UIkit.modal.confirm('Are you sure want to delete items?').then(function () {
            // create hidden input with name delete (for php $_POST['delete'])
            var deleteItem = $(document.createElement('input'));
            deleteItem.attr('type', 'hidden');
            deleteItem.attr('name', 'delete');
            // get parent form
            var form = $('#delete').parents('form');
            // append new hidden input
            form.append(deleteItem);
            // call submit action
            form.submit();
        }, function () {
            console.log('Rejected.')
        });
    });
}

function formSubmitAjax () {
    // 'update' form submitted
    // $('#myForm').ajaxForm({dataType: "json", success: function (data) {alert(data.resp); });
    $('#editForm').ajaxForm({
        dataType: 'json',
        success: function (data) {
            console.log(data);

            if (data.request !== null) {
                UIkit.notification(" "+ data.request.content, data.request.type);
            } else {
                UIkit.notification(" Incorrect form values!", 'warning');
            }
        },
        error: function () {
            UIkit.notification(" AJAX request error!", 'danger');
        }
    });
}

function finderWindowInit() {
    // finder file selection handler
    $('#finder-select').on('click', function (e) {
        $('
').dialogelfinder({
                width: 800,
                height: 500,
                cssAutoLoad : ['/system/vendor/Finder/themes/Material/css/theme-gray.css'],
                url : '/system/vendor/Finder/php/connector.minimal.php',
                getFileCallback: function(file) {
                    $('#editor').dialogelfinder('close');

                    var url = (file.url).replace("/system/vendor/Finder/php/../../../../","");
                    $('#finder-filename').val(url);
                }
            });
    });
}

$(document).ready(function () {
    formDeleteConfirmation();
    // formSubmitAjax();
    finderWindowInit();
});
<file_sep>/system/config/twig/twig_filters.php
<?php

	return array(

		//
        // Pattern Helper
        //
        // Generate HTML form pattern from FormHelper
		// Example => {{ 'login' | pattern }}
        //
		new Twig_Filter(
			'pattern',
			function ($pattern_name) {
				return \deepkit\helpers\FormHelper::$patterns[$pattern_name];
			}
		),

        //
        // Markdown Converter
        //
        // Generate HTML from Markdown content
        // Example => {{ var | markdown }}
        //
        new Twig_Filter(
            'markdown',
            function ($content) {
                return (new \vendor\Markdown\Markdown)->text($content);
            },
            array('is_safe' => array('html'))
        ),

		//
        // Database Widget
        //
        // Render specific position HTML widget from MySQL database by using custom model
		// Exmaple => {{ 'top' | load_widgets }})
        //
		// new Twig_Filter('',function () {}, array('is_safe' => array('html'))),
	);<file_sep>/app/frontend/controllers/CommentController.php
<?php

	namespace frontend\controllers;

	use deepkit\core\Controller;
	use common\models\CommentModel;

	/**
	* Website comments and reviews module
	*/
	class CommentController extends Controller {

		protected function index() {

			/**
			* Generate action view page template
			*
			* arg[0] -> model data
			* arg[1] -> full view
			*/
			$this->generateView(
				(new CommentModel)->index(...$this->data),
				true
			);
		}

		protected function edit() {

			/**
			* Generate action view page template
			*
			* arg[0] -> model data
			* arg[1] -> full view
			*/
			$this->generateView(
				(new CommentModel)->edit(...$this->data),
				true
			);
		}

		protected function delete() {

			/**
			* Generate action view page template
			*
			* arg[0] -> model data
			* arg[1] -> full view
			*/
			$this->generateView(
				(new CommentModel)->delete(...$this->data),
				true
			);
		}

		protected function change_status() {

			/**
			* Generate action view page template
			*
			* arg[0] -> model data
			* arg[1] -> full view
			*/
			$this->generateView(
				(new CommentModel)->change_status(...$this->data),
				true
			);
		}

	}
<file_sep>/system/deepkit/core/Router.php
<?php

	namespace deepkit\core;

	// include some classes
	use deepkit\helpers\ErrorHelper;
	use deepkit\helpers\DataFilter;
	use deepkit\helpers\UrlHelper;
	use deepkit\helpers\DebugHelper;

	use deepkit\core\PluginManager;
	use system\App;

	/**
	* Router URL class for processing requests
	*/
	class Router {

		/**
		* Controller object
		*
		* @var $controller -> Controller class object for execute some action by request
		*/
		private $controller;

		/**
		* Action name
		*
		* @var $action -> Controller action name for execute
		*/
		private $action;

		/**
		* Data array
		*
		* @var $data -> All arguments from $_GET request for transfer into controller action
		*/
		private $data = [];

		/**
		* Request string
		*
		* @var $request -> Base URI request string
		*/
		private $request;

		/**
		* Routes config
		*
		* @var $routes -> Object for loading routing configuration with rules
		*/
		private $routes;

		/**
		* Application side
		*
		* @var $app_side -> Select one of side by request string (frontend | backend)
		*/
		private $app_side;

		/**
		* Application plugin folder
		*
		* @var $plugin_directory -> Select one of side by request string or plugin
		*/
		private $plugin_directory = null;

		/**
		* Construct function
		*
		* Main init function of Router class
		*/
		function __construct() {

			// load routing settings file
			$this->routes = include(PATH . '/system/config/routes.php');

			// get URI from web address
			$this->request = $_SERVER['REQUEST_URI'];

			// get subdirectory name
			$subdirectory = App::$config->paths->subdirectory;

			// remove subdirectory names if exist for clear app request
			if ($subdirectory != DIRECTORY_SEPARATOR) {

				// replace with RegExp
				$this->request = preg_replace("[".$subdirectory."]", "", $this->request);
			}

			// register plugins
			$this->register_plugins();

			// check user access to requested URI
			$this->check_privileges();

			// call clear request function
			$this->clear_request();

			// start request fetch
			$this->process_url();

			// set debug information
			DebugHelper::setBaseData(
				$this->request,
				$this->controller,
				$this->action,
				$this->data
			);
		}

		/**
		* Check privileges
		*
		* Check user session params and manage routing
		*/
		private function check_privileges() {

			// if session or cookie doesn't contain UserAuthentification info
			if (!isset($_SESSION['UserAuth']) && !isset($_COOKIE['UserAuth'])) {

				// check current request for secured rules
				foreach ($this->routes['secured_pages'] as $rule) {

					// if found matches
					if (preg_match("[{$rule}]", $this->request)) {

						// if current page is not auth_page - redirect
						if (!preg_match("[{$this->routes['auth_page']}]", $this->request)) {

							// set REDIRECTED url into session
							$_SESSION['redirected_url'] = App::$config->paths->relative_url . $this->request;

							// redirect to auth page
							header("Location: " . UrlHelper::Url('@' . $this->routes['auth_page']) );
						}
					}
				}
			}
		}

		/**
		* Clear request
		*
		* Check web address and set clear request string
		*/
		private function clear_request() {

			// set default values if request is empty
			if ($this->request == '/' || $this->request == "") {

				// set new request string
				$this->request = "site/index";

				// set app side value
				$this->app_side = 'frontend';
			} else {

				// remove first slash from request string
				$this->request = preg_replace("[^\/]", "", $this->request);

				// check application side (frontend | backend)
				if (preg_match("[^backend]", $this->request)) {

					// set app side value
					$this->app_side = 'backend';

					// remove side from request
					$this->request = preg_replace("[^backend/?]", "", $this->request);

					// set default backend request if empty
					if ($this->request == "/" || $this->request == "") {
						$this->request = "dashboard";
					}

				} else {

					// set app side value
					$this->app_side = 'frontend';
				}

				// clear URL string with DataFilter
				$this->request = DataFilter::Url ($this->request);
			}
		}

		/**
		 * Register plugins for app routing
		 *
		 * @return void
		 */
		private function register_plugins() {
			// create plugin manager instance
			$plugin_manager = new PluginManager();

			// import rules for current plugin
			foreach ($plugin_manager->plugins as $plugin => $content) {
				// if plugin name contains in request
				if (preg_match("[^{$plugin}]", $this->request)) {
					// set app plugin name
					App::$active_plugin = $plugin;

					// change active directory
					$this->plugin_directory = "plugins\\{$plugin}";

					// import all rules for app side
					foreach ($content['rules'][$this->app_side] as $pattern => $rule) {
						$this->routes['rules'][$this->app_side][$pattern] = $rule;
					}

					// foreach loop break
					break;
				}
			}
		}

		/**
		* Process URL request
		*
		* Fetch URI request and split by normal parts
		*/
		private function process_url() {

			// check application side routing rules with current request
			foreach ($this->routes['rules'][$this->app_side] as $pattern => $route) {

				// replace shortcode placeholder
				$pattern = str_replace("*", "([-_0-9a-zA-Zа-яА-Я\/.]+)", $pattern);

				// if matches was found
				if (preg_match("~$pattern~", $this->request)) {

					// replace for new values
					$this->request = preg_replace("~$pattern~", $route, $this->request);
				}
			}

			// split request for get data
			$request_data = explode('/', $this->request);

			// remove first item (plugin name) if exists
			if (!is_null($this->plugin_directory)) array_shift($request_data);

			// set controller name
			$this->controller = (isset($request_data[0]) ? $request_data[0] : 'site');

			// set controller action name
			$this->action = (isset($request_data[1]) ? $request_data[1] : 'index');

			// insert other arguments into data array (start by 2 - controller,action was passed)
			for ($i = 2; $i < count($request_data); $i++) {

				// push value into array
				array_push($this->data, $request_data[$i]);
			}
		}

		/**
		* Start routing
		*
		* Main Router start point for execute controller actions
		*/
		public function Start() {

			// build requested controller name -> example: frontend\controllers\ExampleController
			$controller_name = $this->app_side . '\\controllers\\' . ucfirst($this->controller) . 'Controller';

			// if it's a plugin -> append to plugin directory path
			if (!is_null($this->plugin_directory)) $controller_name = $this->plugin_directory.'\\'.$controller_name;

			// check class exist
			if (class_exists($controller_name)) {

				// get parent class of controller
				$parent_class = class_parents($controller_name);

				// check if Controller exists in parent class name
				if (in_array('deepkit\\core\\Controller', $parent_class)) {

					// check action exists
					if (method_exists($controller_name, $this->action)) {

						// create new controller object with $_GET args
						$controller_object = new $controller_name($this->action, $this->data);

						// try execute controller action
						if ($controller_object) {
							$controller_object->executeAction();
						} else {
							// show error
							ErrorHelper::showError('500', 'Action error');
						}

					} else {
						// show error -> action doesn't exists
						ErrorHelper::showError('404', 'No action routes');
					}

				} else {
					// show error -> class doesn't exists
					ErrorHelper::showError('404', 'Invalid class parents');
				}
			} else {
				// PLUGIN!!!!
				// show error -> file doesn't exists
				ErrorHelper::showError('404', 'No class routes');
			}
		}

		/**
		 * isAjax checking function
		 *
		 * Check Server request variable and return boolean
		 *
		 */
		public static function isAjax() {
			// check XML Http Request exists
			if(isset($_SERVER['HTTP_X_REQUESTED_WITH']) && !empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') {
			    return true;
			} else {
				// if it's simple request
				return false;
			}
		}

	}
<file_sep>/system/config/routes.php
<?php

	return array(

		// Authorization page
		'auth_page' => 'user/login',

		// Deny current pages for guests
		'secured_pages' => [
			'user/profile',
			//'backend'
		],

		// Rewrite URL rules
		'rules' => [

			// Front-End side only
			'frontend' 	=> [
				'home' 		=> 'site/index',
				'page/*'	=> 'page/view/$1',
			],

			// Back-End side only
			'backend' 	=> [
				'dashboard' => 'site/index',
			]

		]

	);
	<file_sep>/app/backend/controllers/UserRoleController.php
<?php

	namespace backend\controllers;

	use deepkit\core\Controller;
	use backend\models\UserRoleModel;

	/**
	* System users roles module
	*/
	class UserRoleController extends Controller {

		protected function index() {

			/**
			* Generate action view page template
			*
			* arg[0] -> model data
			* arg[1] -> full view
			*/
			$this->generateView(
				(new UserRoleModel)->index(...$this->data),
				true
			);
		}

		protected function edit() {

			/**
			* Generate action view page template
			*
			* arg[0] -> model data
			* arg[1] -> full view
			*/
			$this->generateView(
				(new UserRoleModel)->edit(...$this->data),
				true
			);
		}

		protected function delete() {

			/**
			* Generate action view page template
			*
			* arg[0] -> model data
			* arg[1] -> full view
			*/
			$this->generateView(
				(new UserRoleModel)->delete(...$this->data),
				true
			);
		}

	}
<file_sep>/assets/src/frontend.less
// ---------- Import base UIKit core -> (UIKit 3.0.25) ----------
@import "../vendor/uikit3/less/uikit.theme.less";

// ---------- Style variables ----------
@tm-primary-color: 		#fff;
@tm-secondary-color: 	#fff;

@tm-danger-color: 		#fff;
@tm-success-color: 		#fff;
@tm-warning-color: 		#fff;

@tm-hover-color: 		#fff;

// ---------- Overwrite UIKit ----------
//
// (less/uikit/components/variables.less
// OR
// less/uikit/components/COMPONENT.less)

// ---------- Additional UIKit hooks ----------
.hook-form() {
	&:invalid {.uk-form-danger}
	&:not(select):valid:focus {.uk-form-success}
}

// ---------- Create custom rules and classes ----------
html {
	-webkit-font-smoothing: antialiased;
}
input[type="date"]::-webkit-inner-spin-button {
	margin-right: 7px;
	height: 100%;
}
<file_sep>/system/deepkit/helpers/DebugHelper.php
<?php

	namespace deepkit\helpers;

	use deepkit\helpers\DataFilter;
	use system\App;

	/**
	* Debug helper for log some errors or warnings in DebugToolbar
	*/
	class DebugHelper {

		/**
		* Set base data
		*
		* Setting up $_REQUEST, Controller name and action, $_GET args data
		*
		* @param string $request
		* @param string $controller -> controller name
		* @param string $action -> action name
		* @param string $data -> data from request
		*/
		public static function setBaseData($request = null, $controller = null, $action = null, $data = null) {

			// set up variables
			$_SESSION['debug']['request'] = $request;
			$_SESSION['debug']['action'] = $controller . "->" . $action;
			$_SESSION['debug']['data'] = implode(',', $data);
		}

		/**
		* Write data
		*
		* Write same data into session
		*
		* @param string $data -> data for write in Session
		* @param string $type -> type of content
		*/
		private static function writeData($data, $type) {

			// write into session
			if (!isset($_SESSION['debug'][$type])) {

				// init new array
				$_SESSION['debug'][$type] = [];
			}

			// append new value
			array_push($_SESSION['debug'][$type], $data);
		}

		/**
		* Info
		*
		* Write dump information about object into debug toolbar
		*
		* @param object $object -> object for writing
		*/
		public static function info($object) {

			// create object dump
			$message = DataFilter::Dump($object, true);

			// call write data function
			DebugHelper::writeData($message, 'info');
		}

		/**
		* Message
		*
		* Write simple statistics message into debug toolbar
		*
		* @param string $text
		*/
		public static function message($text) {

			// call write data function
			DebugHelper::writeData($text, 'message');
		}

		/**
		* Error
		*
		* Write danger message into specify debug toolbar section
		*
		* @param string $text
		*/
		public static function error($text) {

			// call write data function
			DebugHelper::writeData($text, 'error');
		}

		/**
		* Warning
		*
		* Write warning message into specify debug toolbar section
		*
		* @param string $text
		*/
		public static function warning($text) {

			// call write data function
			DebugHelper::writeData($text, 'warning');
		}

		/**
		* SQL
		*
		* Write SQL query string into specify debug toolbar section
		*
		* @param string $text
		*/
		public static function sql($text) {

			// call write data function
			DebugHelper::writeData($text, 'sql');
		}

		/**
		* Clear Cache
		*
		* Remove all messages after writing into debug toolbar
		*/
		public static function clearCache() {

			// remove from session cache
			if (isset($_SESSION['debug'])) {

				// reset values
				$_SESSION['debug'] = [];

				// unset
				unset($_SESSION['debug']);
			}
		}

		/**
		* Show Toolbar
		*
		* Render HTML toolbar with message sections
		*/
		public static function Render() {

			// if toolbar enabled
			if (App::$config->debug->show_toolbar) {

				// cache session data
				$debug_data = (isset($_SESSION['debug'])) ? $_SESSION['debug'] : [];

				// clear session storage
				DebugHelper::clearCache();

				// set path to widget template
				$template_path = 'common/widgets/debug/debug.html';

				// render template to HTML and write in var
				$template = App::$twig->render(
					$template_path, [
						'debug' => $debug_data,
					]
				);

				// return rendered result
				return $template;
			} else {

				// if debug disabled
				return false;
			}
		}

	}
<file_sep>/app/common/models/WidgetModel.php
<?php

	namespace common\models;

	use deepkit\core\Model;

	use deepkit\helpers\CookieHelper;
	use deepkit\helpers\DataFilter;
	use deepkit\helpers\DebugHelper;
	use deepkit\helpers\ErrorHelper;
	use deepkit\helpers\NotifyHelper;
	use deepkit\helpers\FormHelper;

	/**
	* Module for manage widgets
	*/
	class WidgetModel extends Model {

		/**
		* Table name
		*
		* Override class property 'table_name'
		*/
		protected $table_name = 'system_widget';

		/**
		* Index
		*
		* index action of controller
		*/
		public function index($args = null) {
			$data = [];

			// template view result
			return $data;
		}

		/**
		* Edit
		*
		* edit action of controller
		*/
		public function edit($args = null) {
			$data = [];

			// template view result
			return $data;
		}

		/**
		* Load
		*
		* load action of controller
		*/
		public function load($args = null) {
			$data = [];

			// template view result
			return $data;
		}

		/**
		* Update
		*
		* update action of controller
		*/
		public function update($args = null) {
			$data = [];

			// template view result
			return $data;
		}

		/**
		* Delete
		*
		* delete action of controller
		*/
		public function delete($args = null) {
			$data = [];

			// template view result
			return $data;
		}

		/**
		* Sort
		*
		* sort action of controller
		*/
		public function sort($args = null) {
			$data = [];

			// template view result
			return $data;
		}

		/**
		* Change_status
		*
		* change_status action of controller
		*/
		public function change_status($args = null) {
			$data = [];

			// template view result
			return $data;
		}

	}
<file_sep>/app/backend/models/InformationModel.php
<?php

	namespace backend\models;

	use deepkit\core\Model;

	use deepkit\helpers\CookieHelper;
	use deepkit\helpers\DataFilter;
	use deepkit\helpers\DebugHelper;
	use deepkit\helpers\ErrorHelper;
	use deepkit\helpers\NotifyHelper;
	use deepkit\helpers\FormHelper;

	use system\App;
	use PDO;

	/**
	* System and server information module
	*/
	class InformationModel extends Model {

		/**
		* Table name
		*
		* Override class property 'table_name'
		*/
		protected $table_name = 'null';

		/**
		* Index
		*
		* index action of controller
		*/
		public function index($args = null) {
			$data = [];

            //
            // System information
            //
			// get Deepkit version
            $data['system']['version'] = App::$config->application->version;

            // get web server name string
            $data['system']['server'] = $_SERVER['SERVER_SOFTWARE'];

            // get user agent info
            $data['system']['user_agent'] = $_SERVER['HTTP_USER_AGENT'];

            //
            // PHP information
            //
            // get php version
            $data['php']['version'] = phpversion();

            // get php handler name
            $data['php']['handler'] = php_sapi_name();

            // get php server name
            $data['php']['server'] = php_uname();

            // get php extension list
            $data['php']['modules'] = implode(", ", get_loaded_extensions());

            //
            // Database information
            //
            // get driver name
            $data['db']['driver'] = $this->info['driver'];

            // get version string
            $data['db']['version'] = $this->info['version'];

            // get client name
            $data['db']['client'] = $this->info['client'];

			// template view result
			return $data;
		}

	}
<file_sep>/assets/js/deepkit.js
function checkboxesTable() {
	// check all checboxes in tables
	var checkboxes = $('table').find('input[type="checkbox"]');
	$(checkboxes[0]).on("click", function () {
		for (var i = 1; i < (checkboxes.length + 1); i++) {
			$(checkboxes[i]).prop('checked', !($(checkboxes[i]).prop('checked')) );
		}
	});
}

function csrfTokenInit() {
	// append csrf token
	$("form").each(function() {
		var tokenElement = $(document.createElement('input'));
		tokenElement.attr('type', 'hidden');
		tokenElement.attr('name', 'token');
		tokenElement.val(csrf_token);
		$(this).append(tokenElement);
	});
}

function markdownEditorInit() {
	// enable markdown editor
	if ($('#md').length == 1) {
		var simplemde = new SimpleMDE({ element: $("#md")[0] });
	}
}

$(document).ready(
	function () {
		checkboxesTable();
		csrfTokenInit();
		markdownEditorInit();
	}
);
<file_sep>/app/backend/controllers/PageController.php
<?php

	namespace backend\controllers;

	use deepkit\core\Controller;
	use backend\models\PageModel;

	/**
	* Main page items module
	*/
	class PageController extends Controller {

		protected function index() {

			/**
			* Generate action view page template
			*
			* arg[0] -> model data
			* arg[1] -> full view
			*/
			$this->generateView(
				(new PageModel)->index(...$this->data),
				true
			);
		}

		protected function edit() {

			/**
			* Generate action view page template
			*
			* arg[0] -> model data
			* arg[1] -> full view
			*/
			$this->generateView(
				(new PageModel)->edit(...$this->data),
				true
			);
		}

	}
<file_sep>/system/app.php
<?php

	namespace system;

	// connect some classes
	use deepkit\helpers\ErrorHelper;

	use deepkit\core\Router;

	use Twig_Loader_Filesystem;
	use Twig_Environment;
	use Twig_Function;

	/**
	* Main App class for setup behavior
	*/
	class App {

		/**
		* Config
		*
		* @var object $config -> Global application configuration object
		*/
		public static $config;

		/**
		* Twig
		*
		* @var object $twig -> Global Twig templater object
		*/
		public static $twig;

		/**
		* Page
		*
		* @var array $meta -> Basic meta page information
		*/
		public static $meta;

		/**
		* Active application plugin name
		*
		* Setting up by Router class
		* @var string $active_plugin -> set after some plugin loaded in app
		*/
		public static $active_plugin = null;

		/**
		* App -> Start
		*
		* Main start point for initializing application
		* @param bool $routing -> if routing needed
		*/
		public function Start($routing = true) {

			// load config into object
			App::$config = $this->LoadConfig();

			// FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME
            // load meta info -  FIXME FIXME FIXME FIXME FIXME FIXME FIXME
            // FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME FIXME

			App::$meta = [
				'site_name'		=> 'DeepKit',
				'title' 		=> 'DeepKit - Simple PHP CMF',
				'description' 	=> '',
				'keywords' 		=> '',
				'author'		=> '',
				'icon'			=> 'assets/img/logo.png',
				'logo'			=> 'assets/img/logo-inverse.png',
				'image'			=> '',
				'language'		=> 'ru',
				'url'			=> substr($_SERVER['REQUEST_URI'], 1)
			];

			// session HTTP only
			ini_set('session.cookie_httponly', App::$config->session->http_only);

			// start session with specified name
			session_name(App::$config->session->name);
			session_start();

			// init CSRF token
            if (!isset($_SESSION['token'])) {
                $_SESSION['token'] = App::$config->security->csrf;
            }

			// error display settings
			ini_set('display_errors', App::$config->debug->show_errors);
			error_reporting(App::$config->debug->error_types);

            // instantiate new Twig object
            App::$twig = $this->LoadTwig();

			// if routing enabled
			if ($routing) {
				// create app router
				$router = new Router();

				// start routing
				$router->Start();
			}
		}

		/**
		* Load Config
		*
		* Function for loading main configuration file as object
		*/
		private function LoadConfig() {

			// load base configuration file
			$config = include(PATH . '/system/config/app.php');

			// create empty object for return result
			(object)$config_object = (object)[];

			// convert each array value into object property
			foreach ($config as $key => $value) {
				// object->property = value
				$config_object->{$key} = (object)$value;
			}

			// return new configuration object
			return $config_object;
		}

		/**
		* Load Twig
		*
		* Return global Twig templater object for use in any point of app
		*/
		private function LoadTwig() {

			// setup Twig templates folder
			$templates_folder = new Twig_Loader_Filesystem(
				App::$config->twig->templates
			);

			// setup Twig object
			$twig = new Twig_Environment(
				$templates_folder,
				App::$config->twig->params
			);

			// some filters for Twig object
			$twig_filters = include(PATH . "/system/config/twig/twig_filters.php");

			// add all filters into Twig
			foreach ($twig_filters as $filter) {
				$twig->addFilter($filter);
			}

			// add $_SESSION access global
            $twig->addGlobal('session', $_SESSION);
			// enable dump() function
			$twig->addExtension(new \Twig_Extension_Debug());

			// setup Twig function extension
			include(PATH . "/system/config/twig/twig_functions.php");

			// return new Twig object
			return $twig;
		}

	}
<file_sep>/app/backend/models/PageModel.php
<?php

	namespace backend\models;

	use deepkit\core\Model;

	use deepkit\helpers\UrlHelper;
	use deepkit\helpers\CookieHelper;
	use deepkit\helpers\DataFilter;
	use deepkit\helpers\DebugHelper;
	use deepkit\helpers\ErrorHelper;
	use deepkit\helpers\NotifyHelper;
	use deepkit\helpers\FormHelper;

	/**
	* Main page items module
	*/
	class PageModel extends Model {

		/**
		* Table name
		*
		* Override class property 'table_name'
		*/
		protected $table_name = 'system_page';

		/**
		* Index
		*
		* index action of controller
		*/
		public function index($page = null) {
			$data = [];

			// if submitted change status button
			if (isset($_POST['checked'])) {
				if (isset($_POST['publish'])) {
					$this->change_status($_POST['checked'], 1);
				}
				if (isset($_POST['unpublish'])) {
					$this->change_status($_POST['checked']);
				}
				if (isset($_POST['delete'])) {
					$this->delete($_POST['checked']);
				}
			}

			// set pagination object
			$data['pagination'] = $this->getPagination(
				$this->getCount(),
				$page
			);

			// get all pages from db
			$data['pages'] = $this->getRange(
				$data['pagination']['start'],
				$data['pagination']['items_on_page']
			);

			// template view result
			return $data;
		}

		/**
		* Edit
		*
		* edit action of controller
		*
		* @param int $id
		*/
		public function edit($id = null) {
			$data = [];

			// Update or add submitted
			if (isset($_POST['save'])) {
				$this->update($id);
			}

			// $_GET id requested
			if ($id) {
				// get page by GET id
				$data['page'] = $this->getById($id);
				// if item was found
				if ($data['page']) {
					$data['page']->data = json_decode($data['page']->data);
					// get page meta info
					$this->query("
						select * from system_meta
						where page = :id
					");
					$this->bind(':id', $id);
					$data['page']->meta = $this->findOne();
				} else {
					ErrorHelper::showError('404', 'Page not found!');
				}
			}

			// template view result
			return $data;
		}

		/**
		* Update
		*
		* update action of controller
		*/
		public function update($id = null) {
			$post = $_POST;

			$form = FormHelper::validateForm($_POST, [
				'title' => ['title', 'required'],
				'alias' => ['url-slug', 'requred']
			]);

			if (!$form['valid']) {
				NotifyHelper::setText('Invalid form data!');
				return;
			}

			if ($id && $post) {
				$this->query(
					"
					update {$this->table_name}

					set title=:title,
					alias=:alias,
					content=:content,
					image=:image,
					status=:status,
					data=:data

					where id=:id
					"
				);

				$this->bind(':title',$post['title']);
				$this->bind(':alias',$post['alias']);
				$this->bind(':content',$post['content']);
				$this->bind(':image',$post['image']);
				$this->bind(':status',$post['status']);
				$this->bind(':data',json_encode($post['data']));

				$this->bind(':id', $id);

				if ($this->execute()) {
					// update meta table
					$this->query(
						"
						update system_meta

						set title=:title,
						description=:description,
						keywords=:keywords,
						author=:author

						where page=:id
						"
					);

					$this->bind(':title',$post['meta']['title']);
					$this->bind(':description',$post['meta']['description']);
					$this->bind(':keywords',$post['meta']['keywords']);
					$this->bind(':author',$post['meta']['author']);

					$this->bind(':id', $id);

					NotifyHelper::setResultNotify($this->execute());
				}
			} else if ($id == null && $post) {
				// insert new record
				$this->query(
					"
					insert into system_page (title,alias,content,image,status,data)
					values (:title,:alias,:content,:image,:status,:data)
					"
				);

				$this->bind(':title', $post['title']);
				$this->bind(':alias', $post['alias']);
				$this->bind(':content', $post['content']);
				$this->bind(':image', $post['image']);
				$this->bind(':status', $post['status']);
				$this->bind(':data', json_encode($post['data']));

				if ($this->execute()) {
					$page_id = $this->lastInsertId();
					// create meta record
					$this->query("
						insert into system_meta (title,description,keywords,author,page)
						values (:title,:description,:keywords,:author,:page)
					");

					$this->bind(':title', $post['meta']['title']);
					$this->bind(':description', $post['meta']['description']);
					$this->bind(':keywords', $post['meta']['keywords']);
					$this->bind(':author', $post['meta']['author']);

					$this->bind(':page', $this->lastInsertId());
					header("Location: " . UrlHelper::Url("%page/edit/{$page_id}"));
				}
			}
		}

		/**
		* Delete
		*
		* delete action of controller
		*/
		public function delete($ids = null) {
			$ids = implode(',', $ids);
			// delete meta rows
			$this->query("
				delete from system_meta
				where page in ({$ids})
			");

			$query = $this->execute();

			if ($query) {
				$this->query("
					delete from {$this->table_name}
					where id in ({$ids})
				");

				NotifyHelper::setResultNotify($this->execute());
			} else {
				NotifyHelper::setResultNotify($this->execute());
			}
		}

		/**
		* Change_status
		*
		* change_status action of controller
		*/
		public function change_status($ids = null, $status = 0) {
			$ids = implode(',', $ids);

			$this->query("
				update {$this->table_name}
				set status=:status
				where id in ({$ids})
			");

			$this->bind(':status', $status);

			NotifyHelper::setResultNotify($this->execute());
		}

	}
<file_sep>/app/backend/controllers/InformationController.php
<?php

	namespace backend\controllers;

	use deepkit\core\Controller;
	use backend\models\InformationModel;

	/**
	* System and server information module
	*/
	class InformationController extends Controller {

		protected function index() {

			/**
			* Generate action view page template
			*
			* arg[0] -> model data
			* arg[1] -> full view
			*/
			$this->generateView(
				(new InformationModel)->index(...$this->data),
				true
			);
		}

	}
<file_sep>/app/common/models/SubscriptionsModel.php
<?php

	namespace common\models;

	use deepkit\core\Model;

	use deepkit\helpers\CookieHelper;
	use deepkit\helpers\DataFilter;
	use deepkit\helpers\DebugHelper;
	use deepkit\helpers\ErrorHelper;
	use deepkit\helpers\NotifyHelper;
	use deepkit\helpers\FormHelper;

	/**
	* Module for manage e-mail subscriptions
	*/
	class SubscriptionsModel extends Model {

		/**
		* Table name
		*
		* Override class property 'table_name'
		*/
		protected $table_name = 'system_subscriptions';

		/**
		* Index
		*
		* index action of controller
		*/
		public function index($args = null) {
			$data = [];

			// template view result
			return $data;
		}

		/**
		* Edit
		*
		* edit action of controller
		*/
		public function edit($args = null) {
			$data = [];

			// template view result
			return $data;
		}

		/**
		* Delete
		*
		* delete action of controller
		*/
		public function delete($args = null) {
			$data = [];

			// template view result
			return $data;
		}

		/**
		* Change_status
		*
		* change_status action of controller
		*/
		public function change_status($args = null) {
			$data = [];

			// template view result
			return $data;
		}

	}
<file_sep>/.htaccess
# enable redirect
RewriteEngine on
RewriteBase /

# if file or directory wasn't found
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# redirect to main controller
RewriteRule ^(.*)$ index.php [L]
<file_sep>/app/common/models/UserModel.php
<?php

	namespace common\models;

	use deepkit\core\Model;

	use deepkit\helpers\CookieHelper;
	use deepkit\helpers\DataFilter;
	use deepkit\helpers\DebugHelper;
	use deepkit\helpers\ErrorHelper;
	use deepkit\helpers\NotifyHelper;
	use deepkit\helpers\FormHelper;

	/**
	* Main user logic module (register login etc)
	*/
	class UserModel extends Model {

		/**
		* Table name
		*
		* Override class property 'table_name'
		*/
		protected $table_name = 'system_user';

		/**
		* Index
		*
		* index action of controller
		*/
		public function index($args = null) {
			$data = [];

			// template view result
			return $data;
		}

		/**
		* View
		*
		* view action of controller
		*/
		public function view($args = null) {
			$data = [];

			// template view result
			return $data;
		}

		/**
		* Edit
		*
		* edit action of controller
		*/
		public function edit($args = null) {
			$data = [];

			// template view result
			return $data;
		}

		/**
		* Login
		*
		* login action of controller
		*/
		public function login($args = null) {
			$data = [];

			// template view result
			return $data;
		}

		/**
		* Register
		*
		* register action of controller
		*/
		public function register($args = null) {
			$data = [];

			// template view result
			return $data;
		}

		/**
		* Reset_password
		*
		* reset_password action of controller
		*/
		public function reset_password($args = null) {
			$data = [];

			// template view result
			return $data;
		}

		/**
		* Activate
		*
		* activate action of controller
		*/
		public function activate($args = null) {
			$data = [];

			// template view result
			return $data;
		}

	}
<file_sep>/system/autoload.php
<?php

	// define global path to current directory
	define('PATH', realpath(__DIR__.'/../'));

	// Register new autoload setup
	spl_autoload_register(
		function ($requested_class) {

			// Read config for autoload namespaces
			$autoload_rules = include(
				realpath(PATH.'/system/config/namespaces.php')
			);

			// Manage all autoload rules
			foreach ($autoload_rules as $namespace => $path) {

				// Convert entities for replacement
				$request_path = preg_quote($namespace);

				// Convert entities for rewrite
				$result_path = preg_quote($path);

				// If mathces found
				if (preg_match("[^$request_path]", $requested_class)) {
					// Rewrite class path
					$requested_class = preg_replace("~$request_path~", "$result_path", $requested_class);
				}
			}

			// Replace underscores (PSR-4 fix)
			$requested_class = str_replace("_", "\\", $requested_class);

			// Replace slashes
			$requested_class = str_replace("\\", DIRECTORY_SEPARATOR, $requested_class);

			// Append root directory
			$requested_class = dirname(__DIR__).DIRECTORY_SEPARATOR.$requested_class;

			// Append .php extension
			$requested_class .= '.php';

			// Check file exist
			if (file_exists($requested_class)) {

				// connect class file
				require_once($requested_class);

			} else {

                // debug class loading info
                #echo '
'.$requested_class;

				// show error about class loading and die
				\deepkit\helpers\ErrorHelper::showError('404','Page not found');

			}

		}
	);
<file_sep>/system/database/migrations/migration.base_content.php
<?php

    use deepkit\core\Migrator;
    use deepkit\helpers\DataFilter;

    // create new migration object
    $migrator = new Migrator();

    // insert base content
    $migrator->executeAll([
        "
                INSERT INTO `system_user_role` (`id`, `name`, `alias`)
                VALUES
                    (1, 'admin', 'Administrators'),
                    (2, 'user', 'Authenticates');

            ",
        "
                INSERT INTO `system_user` (`id`, `username`, `password`, `email`, `name`, `status`, `roles`)
                VALUES
                    (1, 'admin', '".DataFilter::GetHash('123123')."', '<EMAIL>', '<NAME>', 1, '1'),
                    (2, 'manager', '".DataFilter::GetHash('123123')."', '<EMAIL>', '<NAME>', 1, '2');

            ",
        "
                INSERT INTO `system_widget` (`id`, `name`, `status`, `pages`, `content`, `roles`, `priority`, `position`, `data`)
                VALUES
                    (1, 'Hero widget', 1, NULL, 'Hero widget content', NULL, 0, 'hero', NULL),
                    (2, 'Top widget', 1, NULL, 'Top widget content', NULL, 0, 'top', NULL),
                    (3, 'Middle left widget', 1, NULL, 'Middle-left widget content', NULL, 0, 'middle-left', NULL),
                    (4, 'Middle right widget', 1, NULL, 'Middle-right widget content', NULL, 0, 'middle-right', NULL),
                    (5, 'Bottom widget', 1, NULL, 'Bottom widget content', NULL, 0, 'bottom', NULL),
                    (6, 'Bottom-left widget', 1, NULL, 'Bottom-left widget content', NULL, 0, 'bottom-left', NULL),
                    (7, 'Bottom-right widget', 1, NULL, 'Bottom-right widget content', NULL, 0, 'bottom-right', NULL);

            ",
        "
                INSERT INTO `system_page` (`id`, `title`, `alias`, `content`, `image`, `status`, `data`)
                VALUES
                    (1, 'First page', 'first-page', 'Hello from \'FIRST PAGE\' !', NULL, 1, NULL),
                    (2, 'Second page', 'second-page', 'Hello from \'SECOND PAGE\' !', NULL, 0, NULL);

            ",
        "
                INSERT INTO `system_meta` (`id`, `title`, `description`, `keywords`, `author`, `page`)
                VALUES
                    (1, 'First page', 'Some text about first page content', 'key,anotherKey,superKey', 'Me', 1),
                    (2, 'Second page', 'Some text about second page content', 'key,anotherKey,superKey', 'Me', 2);

            ",
        "
                INSERT INTO `system_menu` (`id`, `parent_id`, `priority`, `status`, `title`, `link`, `roles`, `data`)
                VALUES
                    (1, 0, 1, 1, 'Home', '/', NULL, NULL),
                    (2, 0, 1, 1, 'First page', '/first-page', NULL, NULL),
                    (3, 0, 1, 1, 'Second page', '/second-page', NULL, NULL);

            ",
        "
                INSERT INTO `system_config` (`id`, `name`, `value`)
                VALUES
                    (1, 'system/title', 'Deepkit Website'),
                    (2, 'system/logo', NULL),
                    (3, 'system/inverse-logo', NULL),
                    (4, 'system/icon', NULL),
                    (5, 'system/language', NULL),
                    (6, 'system/status', NULL),
                    (7, 'system/message', NULL),
                    (8, 'system/pagination_count', 15),
                    (9, 'system/meta_author', NULL),
                    (10, 'system/meta_description', NULL),
                    (11, 'system/meta_keywords', NULL),
                    (12, 'system/code_header', NULL),
                    (13, 'system/code_footer', NULL),
                    (14, 'system/fb_app', NULL),
                    (15, 'system/recaptcha', NULL),
                    (16, 'system/analytics', NULL);

            ",
    ]);
<file_sep>/app/backend/controllers/ConfigController.php
<?php

	namespace backend\controllers;

	use deepkit\core\Controller;
	use common\models\ConfigModel;

	/**
	* Module for set up application configurations
	*/
	class ConfigController extends Controller {

		protected function index() {

			/**
			* Generate action view page template
			*
			* arg[0] -> model data
			* arg[1] -> full view
			*/
			$this->generateView(
				(new ConfigModel)->index(...$this->data),
				true
			);
		}

	}
<file_sep>/system/deepkit/helpers/UrlHelper.php
<?php

	namespace deepkit\helpers;

	use deepkit\helpers\DataFilter;
	use system\App;

	/**
	* Class for generate URL links and convert with rules
	*/
	class UrlHelper {

		/**
		* URL
		*
		* Generate URL string from pattern value
		*
		* @param string $pattern -> relative URL with patterns
		*/
		public static function Url($pattern) {

			// get relative url
			$website_url = App::$config->paths->relative_url;

			// check HTTPS connection
			if (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] == 'on') {
				$website_url = "https://" . $website_url;
			} else {
				$website_url = "http://" . $website_url;
			}

			if ($pattern != "") {
                // set new request from @pattern variable (frontend)
                if (preg_match("/^@/", $pattern)) {
	                $request = str_replace("@", $website_url, $pattern);
                }
                // set new request from %pattern variable (backend)
                if (preg_match("/^%/", $pattern)) {
	                $request = str_replace("%", $website_url."backend/", $pattern);
                }
            } else {
			    $request = $website_url;
            }

			// return new URL value
			return $request;
		}

	}
<file_sep>/app/frontend/controllers/UserController.php
<?php

	namespace frontend\controllers;

	use deepkit\core\Controller;
	use common\models\UserModel;

	/**
	* Users manage module
	*/
	class UserController extends Controller {

		protected function index() {

			/**
			* Generate action view page template
			*
			* arg[0] -> model data
			* arg[1] -> full view
			*/
			$this->generateView(
				(new UserModel)->index(...$this->data),
				true
			);
		}

	}
<file_sep>/app/backend/controllers/StorageController.php
<?php

	namespace backend\controllers;

	use deepkit\core\Controller;
	use backend\models\StorageModel;

	/**
	* Module for processing main app storage directory by Elfinder
	*/
	class StorageController extends Controller {

		protected function index() {

			/**
			* Generate action view page template
			*
			* arg[0] -> model data
			* arg[1] -> full view
			*/
			$this->generateView(
				(new StorageModel)->index(...$this->data),
				true
			);
		}

	}
<file_sep>/app/backend/controllers/SubscriptionsController.php
<?php

	namespace backend\controllers;

	use deepkit\core\Controller;
	use common\models\SubscriptionsModel;

	/**
	* Module for creating and manage system email subscribtions
	*/
	class SubscriptionsController extends Controller {

		protected function index() {

			/**
			* Generate action view page template
			*
			* arg[0] -> model data
			* arg[1] -> full view
			*/
			$this->generateView(
				(new SubscriptionsModel)->index(...$this->data),
				true
			);
		}

        protected function edit() {

            /**
             * Generate action view page template
             *
             * arg[0] -> model data
             * arg[1] -> full view
             */
            $this->generateView(
                (new SubscriptionsModel)->edit(...$this->data),
                true
            );
        }

	}
<file_sep>/app/frontend/models/SiteModel.php
<?php

	namespace frontend\models;

	use deepkit\core\Model;

	use deepkit\helpers\CookieHelper;
	use deepkit\helpers\DataFilter;
	use deepkit\helpers\DebugHelper;
	use deepkit\helpers\ErrorHelper;
	use deepkit\helpers\NotifyHelper;
	use deepkit\helpers\FormHelper;

	/**
	* Main start point of app
	*/
	class SiteModel extends Model {

		/**
		* Table name
		*
		* Override class property 'table_name'
		*/
		protected $table_name = 'system_config';

		/**
		* Index
		*
		* index action of controller
		*/
		public function index($args = null) {
			$data = [];

			// template view result
			return $data;
		}

	}
<file_sep>/system/deepkit/core/Model.php
<?php

	namespace deepkit\core;

	use PDO;
use PDOStatement;
	use deepkit\core\Database;
use deepkit\helpers\DataFilter;
use deepkit\helpers\NotifyHelper;

	/**
	* Model main class
	*/
	class Model extends Database {

		/**
		* Table name
		*
		* Basic table name for default queries execute
		* @var string $table_name
		*/
		protected $table_name = 'model';

		/**
		* Find one
		*
		* Return only one record by SQL query
		*/
		public function findOne() {

			// execute query
			$this->execute();

			// fetch and return query result
			return $this->cursor->fetch(PDO::FETCH_OBJ);
		}

		/**
		* Find all
		*
		* Return all of records by SQL query
		*/
		public function findAll() {

			// execute query
			$this->execute();

			// fetch and return query result
			return $this->cursor->fetchAll(PDO::FETCH_OBJ);
		}

		/**
		* Get list
		*
		* Return all table records without SQL query
		*/
		public function getAll() {

			// prepare query
			$this->query("
				select * from {$this->table_name}
			");

			// return result
			return $this->findAll();
		}

		/**
		* Get range
		*
		* Return all records in range (Example: 0,10) by SQL query
		*
		* @param int $start Start of range
		* @param int $limit Items count for query
		*/
		public function getRange($start = 0, $limit = 100) {

			// prepare query
			$this->query("
				select * from {$this->table_name}
				limit :start,:limit
			");

			// replace bind values
			$this->bind(':start', $start);
			$this->bind(':limit', $limit);

			// return result
			return $this->findAll();
		}

		/**
		* Get by ID
		*
		* Return one record with specific ID
		*
		* @param int $id
		*/
		public function getById($id) {

			// prepare query
			$this->query("
				select * from {$this->table_name}
				where id=:id
			");

			// replace bind values
			$this->bind(':id', $id);

			// return result
			return $this->findOne();
		}

		/**
		* Delete by ID
		*
		* Delete one record with specific ID
		*
		* @param int $id
		*/
		public function deleteById($id) {

			// prepare query
			$this->query("
				delete from {$this->table_name}
				where id=:id
			");

			// replace bind values
			$this->bind(':id', $id);

			// return result
			return $this->execute();
		}

		/**
		* Last insert ID
		*
		* Return last inserted ID as integer number
		*/
		public function lastInsertId() {

			// return last ID number
			return $this->database->lastInsertId();
		}

		/**
		* Get count
		*
		* Return records count in current table
		*/
		public function getCount() {

			// prepare query
			$this->query("
				select count(*) from {$this->table_name}
			");

			// return result
			return ($this->findOne())->{'count(*)'};
		}

		/**
		 * Function for calculate pagination object (Twig)
		 *
		 * @param  int $items_count
		 * @param  int $current_page
		 * @return array $pagination
		 */
		public function getPagination($items_count, $current_page) {
			// set current page number
			$pagination['current_page'] = ($current_page) ? $current_page : 1;
			// set count of items from database
			$pagination['items_count'] = $items_count;
			// load allowed items count
			$this->query('select value from system_config where `name`=:name');
			$this->bind(':name', 'system/pagination_count');
			$pagination['items_on_page'] = (int)($this->findOne())->value;
			// calculate page counter size
			$pagination['pages_count'] = ceil($pagination['items_count'] / $pagination['items_on_page']);
			// build first ID for SQL query
			$pagination['start'] = ($pagination['current_page'] == 1) ? 0 : (
				($pagination['current_page'] * $pagination['items_on_page']) - $pagination['items_on_page']
			);

			// return result object
			return $pagination;
		}

	}
<file_sep>/system/config/twig/twig_functions.php
<?php

	//
	// URL Helper function
	//
	// Generate current URL string
	// Example front-end => {{ url('@page/view') }}
	// Example back-end  => {{ url('%page/view') }}
	//
	$twig->addFunction(
		new Twig_Function('url', function ($value) {
	        return \deepkit\helpers\UrlHelper::Url($value);
	    })
	);

	//
	// Notify Helper function
	//
	// Render notify message from session storage
	// Example => {{ notify() }}
	//
	$twig->addFunction(
		new Twig_Function('notify', function () {
			\deepkit\helpers\NotifyHelper::showText();
		})
	);

	//
    // Render Widget
    //
    // Render some PHP widget from 'app/common/widgets' directory
	// Exmaple => {{ widget('test') }}
    //
    $twig->addFunction(
	    new Twig_Function('widget', function ($widget) {
		    // build full class path
			$widget_class = "\\common\\widgets\\{$widget}\\".ucfirst($widget)."Widget";

			// if class exists - return rendered view
			echo (class_exists($widget_class)) ? (new $widget_class)->html() : false;
	    })
    );
	<file_sep>/system/deepkit/core/Database.php
<?php

	namespace deepkit\core;

	use PDO;
	use system\App;
	use deepkit\helpers\ErrorHelper;

	/**
	* Model main class
	*/
	class Database {

		/**
		* Database
		*
		* @var $database -> Database connnection object for operate some functions
		*/
		protected $database;

		/**
		* Cursor
		*
		* @var $cursor -> Database cursor object for process queries
		*/
		protected $cursor;

		/**
		* Configuration
		*
		* @var $config -> Database configuration from App::$config section
		*/
		private $config;

        /**
         * Information
         *
         * @var $info -> Database configuration from App::$config section
         */
        protected $info;

		/**
		* Constructor
		*
		* Main class init function
		*/
		public function __construct() {

			// load config from App
			$this->config = App::$config->database;

			// prepare connection string
			$connection_string = "mysql:host=".$this->config->host.";dbname=".$this->config->database.";charset=utf8";

			// try connect to database
			try {

				// make connection
				$this->database = new PDO (
					$connection_string,
					$this->config->user,
					$this->config->password
				);

				// set information about connection
                $this->info = [
                    'driver'    => $this->database->getAttribute(PDO::ATTR_DRIVER_NAME),
                    'version'   => $this->database->getAttribute(PDO::ATTR_SERVER_VERSION),
                    'client'    => $this->database->getAttribute(PDO::ATTR_CLIENT_VERSION)
                ];

			} catch (\PDOException $ex) {

                // get error code for generate error page
			    $code_error = $ex->getCode();

			    // construct error message by code
                switch ($code_error) {
                    case 1045:
                        $message = 'Access denied for current user';
                    break;
                    case 1046:
                        $message = 'No database selected';
                    break;
                    case 1049:
                        $message = 'Unknown database';
                        break;

                    default:
                        $message = 'Database connection error';
                    break;
                }

				// show database connection error
				ErrorHelper::showError('Database - '.$code_error, $message);
			}
		}

		/**
		* Query
		*
		* Prepare query string for execute in database
		* @param string $sql -> SQL query string
		*/
		public function query($sql) {

			// prepare SQL for execute
			$this->cursor = $this->database->prepare($sql);
		}

		/**
		* Bind
		*
		* Bind some value to specific key in query string
		* @param string $key -> what need replace
		* @param string $value -> value for replacing
		*/
		public function bind($key, $value) {

			// set data of type
			switch (true) {
				case is_int($value):
					$type = PDO::PARAM_INT; // integer number
					break;
				case is_bool($value):
					$type = PDO::PARAM_BOOL; // boolean value
					break;
				case is_null($value):
					$type = PDO::PARAM_NULL; // empty value
					break;
				default:
					$type = PDO::PARAM_STR; // simple string
			}

			// bind values to SQL args
			$this->cursor->bindValue($key, $value, $type);
		}

		/**
		* Execute
		*
		* Execute prepared query string in database
		*/
		public function execute() {

			// execute SQL and return result
			return $this->cursor->execute();
		}

	}
<file_sep>/system/deepkit/helpers/MailHelper.php
<?php

	namespace deepkit\helpers;

	use system\App;

	/**
	* Class for send emails with SMTP Mailer
	*/
	class MailHelper {

		/**
		* Send
		*
		* Send mail template (HTML page) with some values
		*
		* Variables: [sitename, title, content, from, website url, unsubscribe link]
		*
		* @param string $to -> 'To' email address
		* @param array $vars -> letter variables
		*/
		public function Send($to, $vars) {

			// Replacement data
			$vars = [
				'sitename' 		=> '',
				'title' 		=> '',
				'content' 		=> '',
				'from' 			=> '',
				'website' 		=> '',
				'unsubscribe' 	=> '',
			];

			// path to HTML template page
			$template_path = 'templates/mail.html';

			// set encoding for headers
			$title 		= "=?UTF-8?B?" . base64_encode($vars['title']) . "?=";
			$from_user 	= "=?UTF-8?B?" . base64_encode($vars['sitename']) . "?=";

			// set additional headers
			$headers  = "From: $from_user < {$vars['from']} >\n";
			$headers .= "X-Sender: $from_user < {$vars['from']} >\n";
			$headers .= "X-Mailer: PHP/". phpversion();
			$headers .= "X-Priority: 1\n";
			$headers .= "Return-Path: {$vars['from']}";
			$headers .= "MIME-Version: 1.0\r\n";
			$headers .= "Content-type: text/html; charset=ut-8\r\n";
			$headers .= "Reply-To: {$vars['from']}\r\n";

			// render mail page template
			$template = App::$twig->render(
				$template_path,
				$vars
			);

			// send mail function
			return mail(
				$to,
				$title,
				$template,
				$headers,
				"-f{$vars['from']}"
			);

		}

	}
<file_sep>/system/deepkit/core/Widget.php
<?php

	namespace deepkit\core;

	use system\app as App;
	use deepkit\core\Database;

	/**
	* PHP Code widget class
	*/
	class Widget extends Database {

		/**
		* Template file
		*
		* @var string $template -> File name of HTML template folder
		*/
		protected $template = 'test';

		/**
		* Get One
		*
		* Function for fetch one row of executed query
		*/
		protected function getOne() {

			// execute query
			$this->execute();

			// fetch and return query result
			return $this->cursor->fetch(\PDO::FETCH_OBJ);
		}

		/**
		* Get All
		*
		* Fetch all rows of executed query
		*/
		protected function getAll() {

			// execute query
			$this->execute();

			// fetch and return query result
			return $this->cursor->fetchAll(\PDO::FETCH_OBJ);
		}

		/**
		* Get data (for override)
		*
		* Main function for processing data from DB or other sources
		* and generate HTML content
		*/
		protected function data() {

			// return null value
			return false;
		}

		/**
		* HTML
		*
		* Return Twig template render
		*/
		public function html() {

			$template_path = 'common/widgets/'.$this->template.'/view.html';

			return App::$twig->render(
				$template_path,
				$this->data()
			);
		}

	}
<file_sep>/system/deepkit/helpers/CookieHelper.php
<?php

	namespace deepkit\helpers;

	use system\App;

	/**
	* Cookie setup helper
	*/
	class CookieHelper {

		/**
		* Set cookie
		*
		* Set $_COOKIE object with JSON encode
		*
		* @param string $name -> key name for cookie object
		* @param string $object -> value for cookie object
		*/
		public static function Set($name, $object) {

			// encode object into JSON
			$object = json_encode($object);

			// set cookie method
			setcookie(
				$name,
				$object,
				App::$config->session['life_time'],
				'/',
				false, false,
				App::$config->session['http_only']
			);
		}

		/**
		* Get cookie
		*
		* Get JSON-decoded object from $_COOKIE or false
		*
		* @param string $name -> cookie object key
		*/
		public static function Get($name) {

			// check cookie by name exists
			if (isset($_COOKIE[$name])) {

				// get requested value
				$result = json_decode($_COOKIE[$name], true);

				// return result object
				return $result;

			} else {

				return false;
			}
		}

	}

languages: Markdown ApacheConf JavaScript PHP Less

repo_name: Manchenkoff/deepkit-old