Избавляемся от статических классов и синглтонов

This commit is contained in:
CORP\phedor 2018-03-27 12:23:58 +03:00
parent 77fa3dbd5e
commit 805fb6654d
11 changed files with 177 additions and 309 deletions

View file

@ -304,12 +304,12 @@ class Controller_Action
/** /**
* Добавление widget к отображению * Добавление widget к отображению
*/ */
public function addChild(/*Widget*/ $section, $node) public function addChild(/*Widgets_Widget*/ $section, $node)
{ {
$this->childNodes[$section] = $node; $this->childNodes[$section] = $node;
} }
public function setValue(/*Widget*/ $name, $value) public function setValue(/*Widgets_Widget*/ $name, $value)
{ {
$this->ctrlValues[$name] = $value; $this->ctrlValues[$name] = $value;
} }

View file

@ -18,15 +18,12 @@ class Controller_Front extends Controller_Action
* @param Settings $_registry * @param Settings $_registry
* @param Shortcut $_shortcut * @param Shortcut $_shortcut
*/ */
public function __construct(Settings $_registry, $_shortcut) // $db, $installer, $shortcut public function __construct($db, $settings, $default) // $db, $installer, $shortcut
{ {
parent::__construct(); parent::__construct();
$registry = $_registry; $this->settings = $settings;
$this->_registry = $_registry; $this->db = $db;
$this->_shortcut = $_shortcut; // $cc->newShortcut(); $this->default = $default;
$dsn = $registry->readKey(array('system', 'dsn'));
$this->db = Database::getConnection($dsn); // $cc->newConnection();
} }
public function isLoaded($name) public function isLoaded($name)
@ -47,34 +44,24 @@ class Controller_Front extends Controller_Action
return $module->access->execute($request); return $module->access->execute($request);
} }
if ($controller) { $basePath = $this->settings['system']->readKey(['path', 'modules']);
$moduleFile = Shortcut::getUrl($this->shortcut, $name, $controller); // ModuleLoader (2) $moduleFile = Path::join($basePath, $name, 'classes', $controller ? $controller : $name);
} else {
$moduleFile = Shortcut::getUrl($this->shortcut, $name, $name); // ModuleLoader (2)
}
$module = $this->loadClass($moduleFile, null, 'Module_'); $module = $this->loadClass($moduleFile, null, 'Module_');
if ($module) { if ($module) {
// Инициализация модуля // Инициализация модуля
$module->viewPath = Shortcut::getUrl('modulepath', $name); $modPath = Path::join($basePath, $name);
$module->viewPath = $modPath;
$module->name = $name; $module->name = $name;
$module->param = $this->param;
// //
$module->_registry = $this->_registry; $module->settings = $this->settings;
$module->_shortcut = $this->_shortcut;
$module->iconPath = $this->iconPath; // -> Registry
$module->themePath = $this->themePath; // -> Registry
$module->jsPath = $this->jsPath; // -> Registry
$module->db = $this->db; $module->db = $this->db;
// Не для всех приложений нужно вести лог действий
// Ведение лога // Ведение лога
$logger = $this->loadClass(__DIR__ . '/../Filter/ActionLogger.php', $module, 'Filter_'); $logger = new Filter_ActionLogger($module);
$logger->before = $this->loadSettings(Shortcut::getUrl('logger', $name)); $logger->before = $this->loadSettings(Path::join($modPath, 'filter', 'logger.php'));
// Управление доступом // Управление доступом
$module->access = $this->loadClass(__DIR__ . '/../Filter/ActionAccess.php', $logger, 'Filter_'); $module->access = new Filter_ActionAccess($logger);
$module->access->access = $this->loadSettings(Shortcut::getUrl('access', $name)); $module->access->access = $this->loadSettings(Path::join($modPath, 'filter', 'access.php'));
$module->setUp(); $module->setUp();
@ -85,27 +72,19 @@ class Controller_Front extends Controller_Action
return null; // throw new FileNotFoundException(); return null; // throw new FileNotFoundException();
} }
public function setParameter($shortcut, $param, $name)
{
$this->shortcut = $shortcut;
// Параметр
$this->_param = $param;
$this->default = $name;
}
public function execute(HTTPRequest $request) public function execute(HTTPRequest $request)
{ {
$name = explode("_", $request->get($this->_param, $this->default)); $name = explode("_", $request->get('module', $this->default));
if (count($name) >= 2) { if (count($name) >= 2) {
$controller = $name[1]; $controller = $name[1];
} else { } else {
$controller = false; $controller = false;
} }
try{ try {
return $this->loadModule($name[0], $request, $controller); return $this->loadModule($name[0], $request, $controller);
} catch (UserMessageException $ex) { //Исключение с понятным пользователю сообщением } catch (UserMessageException $ex) { //Исключение с понятным пользователю сообщением
$mode = $request->get('mode'); $mode = $request->get('mode');
if($mode == 'ajax' || $mode == 'json'){ if($mode == 'ajax' || $mode == 'json') {
return json_encode(['result'=>'fail', 'message'=> $ex->userMessage]); return json_encode(['result'=>'fail', 'message'=> $ex->userMessage]);
} else { } else {
return $ex->userMessage; return $ex->userMessage;

View file

@ -14,11 +14,11 @@ class Filter_Login extends Filter_Filter
const SESSION_BROWSER_SIGN_KEYNAME = 'session.app.browser.sign'; const SESSION_BROWSER_SIGN_KEYNAME = 'session.app.browser.sign';
public $mode = 'ajax'; public $mode = 'ajax';
//AJAX-Реквесты для которых не требуется авторизация, потребовалось для сбора статистики function __construct($processor, $role, $whitelist = []) {
public $whiteRequestList = [['module' => "requiredcontent", "action" => "getcount"], parent::__construct($processor);
['module' => "requiredcontent", "action" => "teststructure"], $this->role = $role;
['module' => "requiredcontent", "action" => "specialdump"] $this->whitelist = $whitelist;
]; }
/** /**
* Проверка авторизации * Проверка авторизации
* @return Boolean Авторизовани пользователь или нет * @return Boolean Авторизовани пользователь или нет
@ -27,29 +27,18 @@ class Filter_Login extends Filter_Filter
{ {
// Авторизация // Авторизация
session_start(); session_start();
$db = $this->getConnection();
Filter_UserAccess::setUp($db); // Соединение
switch ($request->getAction()) { switch ($request->getAction()) {
// Авторизация по постоянному паролю // Авторизация по постоянному паролю
case 'login': case 'login':
$login = $request->get('login'); $login = $request->get('login');
$password = $request->get('password'); $password = $request->get('password');
$result = Filter_UserAccess::getUserByLogin($login); // Поиск по логину $result = $this->role->getUserByLogin($login); // Поиск по логину
if ($result) { if ($result) {
$userPassword = $result->getString('password'); $userPassword = $this->role->getUserPassword($result);
if (Filter_UserAccess::$access == 'site_root' && defined('PARENT_PATH')) {
$s = new Settings(PARENT_PATH . '/settings.json');
$s->read();
$dsn = $s->readKey(array('system', 'dsn'));
$db = Database::getConnection($dsn);
$user = $db->fetchOneArray("SELECT * FROM users WHERE login = :login", ['login' => $login]);
$userPassword = $user['password'];
}
// Извлечнеие пользователя из родительской CMS, для проверки пароля // Извлечнеие пользователя из родительской CMS, для проверки пароля
if (md5($password) == $userPassword) { // password if (md5($password) == $userPassword) { // password
$this->enter($db, $result); $this->enter($result);
return true; return true;
} }
} }
@ -62,7 +51,7 @@ class Filter_Login extends Filter_Filter
case 'enter': case 'enter':
$login = $request->get('login'); $login = $request->get('login');
$password = $request->get('sid'); $password = $request->get('sid');
$result = Filter_UserAccess::getUserByLogin($login); // Поиск по логину $result = $this->role->getUserByLogin($login); // Поиск по логину
if ($result) { if ($result) {
$temp = md5($result->getString('password') . $result->getString('login') . $result->getString('sid')); $temp = md5($result->getString('password') . $result->getString('login') . $result->getString('sid'));
if ($password == $temp) { if ($password == $temp) {
@ -76,7 +65,7 @@ class Filter_Login extends Filter_Filter
// Если $hash не совпадает $_SESSION['hash'] то удаляем сессию // Если $hash не совпадает $_SESSION['hash'] то удаляем сессию
if (isset($_SESSION ['access']) && isset($_SESSION[self::SESSION_BROWSER_SIGN_KEYNAME])) { if (isset($_SESSION ['access']) && isset($_SESSION[self::SESSION_BROWSER_SIGN_KEYNAME])) {
if ($hash == $_SESSION[self::SESSION_BROWSER_SIGN_KEYNAME]) { if ($hash == $_SESSION[self::SESSION_BROWSER_SIGN_KEYNAME]) {
$this->user = $user = Filter_UserAccess::getUserById($_SESSION['access']); // Поиск по идентификатору $this->user = $user = $role->getUserById($_SESSION['access']); // Поиск по идентификатору
if ($user && isset($_SESSION['random']) && ($user->get('sid') == $_SESSION['random'])) { if ($user && isset($_SESSION['random']) && ($user->get('sid') == $_SESSION['random'])) {
return true; return true;
} }
@ -89,8 +78,7 @@ class Filter_Login extends Filter_Filter
return false; return false;
} }
private function getBrowserSign() private function getBrowserSign() {
{
$rawSign = self::SESSION_BROWSER_SIGN_SECRET; $rawSign = self::SESSION_BROWSER_SIGN_SECRET;
//$signParts = array('HTTP_USER_AGENT', 'HTTP_ACCEPT_ENCODING'); //$signParts = array('HTTP_USER_AGENT', 'HTTP_ACCEPT_ENCODING');
$signParts = array(); $signParts = array();
@ -101,15 +89,15 @@ class Filter_Login extends Filter_Filter
return md5($rawSign); return md5($rawSign);
} }
private function enter($db, $result) private function enter($result)
{ {
$this->user = $result; $this->user = $result;
$random = rand(0, 1024 * 1024); $random = rand(0, 1024 * 1024);
$db->executeQuery("UPDATE users SET sid = '$random' WHERE id_user = " . $result->getInt('id_user')); $this->role->setSID($random, $result);
$_SESSION["group"] = $result->getInt('access'); // $_SESSION["group"] = $result->getInt('access');
$_SESSION["access"] = $result->getInt('id_user'); // id_user $_SESSION["access"] = $result->getInt('id_user');
$_SESSION["random"] = $random; // id_user $_SESSION["random"] = $random;
$_SESSION[self::SESSION_BROWSER_SIGN_KEYNAME] = $this->getBrowserSign(); $_SESSION[self::SESSION_BROWSER_SIGN_KEYNAME] = $this->getBrowserSign();
$_SESSION["time"] = time(); $_SESSION["time"] = time();
} }
@ -122,7 +110,6 @@ class Filter_Login extends Filter_Filter
$result = array(); $result = array();
$result['fullname'] = $this->user->getString('patronymic') . " " . $this->user->getString('firstname'); $result['fullname'] = $this->user->getString('patronymic') . " " . $this->user->getString('firstname');
$result['email'] = $this->user->getString('email'); $result['email'] = $this->user->getString('email');
$result['site'] = 187;
$result['hash'] = sha1(self::SESSION_BROWSER_SIGN_SECRET . $this->user->getString('email')); $result['hash'] = sha1(self::SESSION_BROWSER_SIGN_SECRET . $this->user->getString('email'));
return json_encode($result); return json_encode($result);
} else { } else {
@ -164,7 +151,6 @@ class Filter_Login extends Filter_Filter
/* --------------------- /* ---------------------
* Проверка на попадание реквеста в белый список * Проверка на попадание реквеста в белый список
*/ */
public function requestIsWhite(Collection $request, $whiteRequestList){ public function requestIsWhite(Collection $request, $whiteRequestList){
$module = $request->get('module'); $module = $request->get('module');
$action = $request->get('action'); $action = $request->get('action');

View file

@ -1,69 +0,0 @@
<?php
// Класс должен быть в библиотеке приложения
class Filter_UserAccess
{
const LIFE_TIME = 1800; // = 30min * 60sec;
static $fullname;
static $name;
static $access;
static $password;
static $id;
static $db;
protected function __construct()
{
}
public static function setUp(Database $db)
{
self::$db = $db;
}
public static function getUserByQuery(Database_Statement $stmt)
{
global $GROUPS;
$result = $stmt->executeQuery();
if ($result->next()) {
self::$access = $GROUPS[$result->getString('access')];
self::$name = $result->getString('login');
self::$id = $result->getInt('id_user');
self::$password = $result->getString('password');
self::$fullname = implode(' ', array(
$result->getString('surname'),
$result->getString('firstname'),
$result->getString('patronymic')));
return $result;
}
return null;
}
public static function getUserByLogin($login)
{
$stmt = self::$db->prepareStatement("SELECT * FROM users WHERE login = ?");
$stmt->setString(1, $login);
$result = self::getUserByQuery($stmt);
if ($result) {
$time = time();
$id = self::$id;
self::$db->executeQuery("UPDATE users SET lasttime = $time WHERE id_user = $id"); // Время входа
}
return $result;
}
public static function getUserById($id)
{
$stmt = self::$db->prepareStatement("SELECT * FROM users WHERE id_user = ?");
$stmt->setInt(1, $_SESSION ['access']);
$result = self::getUserByQuery($stmt);
if ($result) {
$lasttime = $result->getInt('lasttime');
$time = time();
if ($time - $lasttime > self::LIFE_TIME) return null; // Вышло время сессии
$id = self::$id;
self::$db->executeQuery("UPDATE users SET lasttime = $time WHERE id_user = $id"); // Время последнего обращения входа
}
return $result;
}
}

View file

@ -1,24 +0,0 @@
<?php
///<reference path="Settings.php" />
/**
* http://www.patternsforphp.com/wiki/Registry
* http://www.patternsforphp.com/wiki/Singleton
* http://www.phppatterns.com/docs/design/the_registry?s=registry
*/
class Registry extends Settings
{
static $instance = null;
/**
*/
static public function getInstance ()
{
if (self::$instance == null) {
self::$instance = new Registry();
}
return self::$instance;
}
}

69
src/Role/User.php Normal file
View file

@ -0,0 +1,69 @@
<?php
// Класс должен быть в библиотеке приложения
class Role_User
{
const LIFE_TIME = 1800; // = 30min * 60sec;
public $fullname;
public $name;
public $access;
public $password;
public $id;
public $db;
protected function __construct()
{
}
public function setDB(Database $db)
{
$this->db = $db;
}
public function getUserByQuery(Database_Statement $stmt)
{
global $GROUPS;
$result = $stmt->executeQuery();
if ($result->next()) {
$this->access = $GROUPS[$result->getString('access')];
$this->name = $result->getString('login');
$this->id = $result->getInt('id_user');
$this->password = $result->getString('password');
$this->fullname = implode(' ', array(
$result->getString('surname'),
$result->getString('firstname'),
$result->getString('patronymic')));
return $result;
}
return null;
}
public static function getUserByLogin($login)
{
$stmt = $this->$db->prepareStatement("SELECT * FROM users WHERE login = ?");
$stmt->setString(1, $login);
$result = $this->getUserByQuery($stmt);
if ($result) {
$time = time();
$id = $this->id;
$this->$db->executeQuery("UPDATE users SET lasttime = $time WHERE id_user = $id"); // Время входа
}
return $result;
}
public static function getUserById($id)
{
$stmt = $this->$db->prepareStatement("SELECT * FROM users WHERE id_user = ?");
$stmt->setInt(1, $_SESSION ['access']);
$result = $this->getUserByQuery($stmt);
if ($result) {
$lasttime = $result->getInt('lasttime');
$time = time();
if ($time - $lasttime > $this->LIFE_TIME) return null; // Вышло время сессии
$id = $this->$id;
$this->db->executeQuery("UPDATE users SET lasttime = $time WHERE id_user = $id"); // Время последнего обращения входа
}
return $result;
}
}

View file

@ -34,7 +34,7 @@ class Settings extends Collection
if ($this->format == 'json') { if ($this->format == 'json') {
$settings = json_decode(File::getContents($this->file), true); $settings = json_decode(File::getContents($this->file), true);
} else { } else {
include ($this->file); $settings = include ($this->file);
} }
if (!is_array($settings)) { if (!is_array($settings)) {
@ -165,7 +165,7 @@ class Settings extends Collection
$result = json_encode($this->data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE); $result = json_encode($this->data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
} else { } else {
$result = var_export($this->data, true); $result = var_export($this->data, true);
$result = "<?php\n\$settings = ".$result.";\n?>"; $result = "<?php\nreturn ".$result.";\n?>";
} }
file_put_contents (($file) ? $file : $this->file, $result); file_put_contents (($file) ? $file : $this->file, $result);
} }

View file

@ -1,66 +0,0 @@
<?php
/**
* Класс для короткого доступа к файлам / папкам
*/
class Shortcut
{
static $instance = null;
public $variables = array();
public $list = array();
// Singleton pattern
static public function getInstance()
{
if (self::$instance == null) {
self::$instance = new Shortcut();
}
return self::$instance;
}
/**
* Добавляет ярлык с именем $prefix
* Путь может содержать переменные
*/
public function addUrl($prefix, $path)
{
$this->list[$prefix] = $path;
}
/**
*
*/
public function addVar($name, $value)
{
$this->variables['$' . $name] = $value;
}
/**
* Возвращает путь по имени ярлыка
*/
static function getUrl($prefix, $name = null, $name1 = null)
{
$shortcut = self::getInstance();
$names = $shortcut->variables;
if ($name) {
$names['$name'] = $name;
}
if ($name1) {
$names['$name1'] = $name1;
}
if (isset($shortcut->list[$prefix])) {
return strtr($shortcut->list[$prefix], $names);
}
return null;
}
static function expand($path)
{
$shortcut = self::getInstance();
$names = $shortcut->variables;
return strtr($path, $names);
}
}

72
src/Tales.php Normal file
View file

@ -0,0 +1,72 @@
<?php
/**
* Расширения для PHPTAL для отображения времени и даты
*/
class DateTime_Tales implements PHPTAL_Tales
{
static public function date($expression, $nothrow = false)
{
return "Tales::phptal_date(".PHPTAL_Php_TalesInternal::path ($expression).")";
}
static public function time($expression, $nothrow = false)
{
return "Tales::phptal_time(".PHPTAL_Php_TalesInternal::path ($expression).")";
}
}
/**
* TALES для подключения компонентов
* component:name?param1=value1&param2=value2
*/
class Component_Tales implements PHPTAL_Tales
{
static public function component($expression, $nothrow = false)
{
$s = PHPTAL_Php_TalesInternal::string($expression);
return "Tales::phptal_component(" . $s . ")";
}
}
class Tales {
static function phptal_date ($e) {
return date("d.m.Y", $e);
}
static function phptal_time ($e) {
return date("H:i", $e);
}
/**
* Функция подключения компонента
*/
static function phptal_component ($expression) {
$begin = floatval(microtime(true));
/*.Controller_Component.*/$component = null;
if (class_exists("Controller_Site")) { //Если мы в CMS2
$component = Controller_Site::loadComponent($expression);
} else {
global $db, $registry; // Иначе обращаемся к глобальным переменным
$component = Controller_Component::loadComponent($expression, $db, $registry);
}
$req = new HttpRequest();
$result = $component->execute($req);
echo "<!-- ", $expression, ", ", round(floatval(microtime(true)) - $begin, 4), "sec -->";
return $result;
}
static function register() {
/* Регистрация нового префикса для подключения компонента */
$tales = PHPTAL_TalesRegistry::getInstance();
$tales->registerPrefix('component', array('Component_Tales', 'component'));
$tales->registerPrefix('date', array('DateTime_Tales', 'date'));
$tales->registerPrefix('time', array('DateTime_Tales', 'time'));
}
}

View file

@ -1,8 +0,0 @@
<?php
function loadConfig($filename) {
if (@include($filename)) {
return $settings;
}
throw new Exception("config $filename not found");
}

View file

@ -1,71 +0,0 @@
<?php
/**
* Расширения для PHPTAL для отображения времени и даты
*/
class DateTime_Tales implements PHPTAL_Tales
{
static public function date($expression, $nothrow = false)
{
return "phptal_date(".PHPTAL_Php_TalesInternal::path ($expression).")";
}
static public function time($expression, $nothrow = false)
{
return "phptal_time(".PHPTAL_Php_TalesInternal::path ($expression).")";
}
}
/**
* TALES для подключения компонентов
* component:name?param1=value1&param2=value2
*/
class Component_Tales implements PHPTAL_Tales
{
static public function component($expression, $nothrow = false)
{
$s = PHPTAL_Php_TalesInternal::string($expression);
return "phptal_component(" . $s . ")";
}
}
function phptal_date ($e)
{
return date("d.m.Y", $e);
}
function phptal_time ($e)
{
return date("H:i", $e);
}
/**
* Функция подключения компонента
*/
function phptal_component ($expression) {
$begin = floatval(microtime(true));
/*.Controller_Component.*/$component = null;
if (class_exists("Controller_Site")) { //Если мы в CMS2
$component = Controller_Site::loadComponent($expression);
} else {
global $db, $registry; // Иначе обращаемся к глобальным переменным
$component = Controller_Component::loadComponent($expression, $db, $registry);
}
$req = new HttpRequest();
$result = $component->execute($req);
echo "<!-- ", $expression, ", ", round(floatval(microtime(true)) - $begin, 4), "sec -->";
return $result;
}
/* Регистрация нового префикса для подключения компонента */
$tales = PHPTAL_TalesRegistry::getInstance();
$tales->registerPrefix('component', array('Component_Tales', 'component'));
$tales->registerPrefix('date', array('DateTime_Tales', 'date'));
$tales->registerPrefix('time', array('DateTime_Tales', 'time'));