substates for the statesystem, many optimizations

This commit is contained in:
Ulf Gebhardt 2015-04-10 00:17:14 +02:00
parent 8ff0efe6ba
commit b3414fc398
11 changed files with 207 additions and 83 deletions

View File

@ -7,11 +7,11 @@ class SYS_PAGE_GROUP extends \SYSTEM\DB\QP {
//pg //pg
'SELECT * FROM '.\SYSTEM\DBD\system_page::NAME_PG 'SELECT * FROM '.\SYSTEM\DBD\system_page::NAME_PG
.' WHERE "'.\SYSTEM\DBD\system_page::FIELD_GROUP.'" = $1' .' WHERE "'.\SYSTEM\DBD\system_page::FIELD_GROUP.'" = $1'
.' AND "'.\SYSTEM\DBD\system_page::FIELD_ID.'" = $2' .' AND "'.\SYSTEM\DBD\system_page::FIELD_STATE.'" = $2'
.' ORDER BY "'.\SYSTEM\DBD\system_page::FIELD_ID.'"', .' ORDER BY "'.\SYSTEM\DBD\system_page::FIELD_ID.'" ASC;',
//mys //mys
'SELECT * FROM '.\SYSTEM\DBD\system_page::NAME_MYS 'SELECT * FROM '.\SYSTEM\DBD\system_page::NAME_MYS
.' WHERE `'.\SYSTEM\DBD\system_page::FIELD_GROUP.'` = ?' .' WHERE `'.\SYSTEM\DBD\system_page::FIELD_GROUP.'` = ?'
.' AND `'.\SYSTEM\DBD\system_page::FIELD_ID.'` = ?' .' AND `'.\SYSTEM\DBD\system_page::FIELD_STATE.'` = ?'
.' ORDER BY '.\SYSTEM\DBD\system_page::FIELD_ID .' ORDER BY '.\SYSTEM\DBD\system_page::FIELD_ID.' ASC;'
);}} );}}

View File

@ -1,11 +1,16 @@
CREATE TABLE `system_page` ( CREATE TABLE `system_page` (
`id` INT(10) UNSIGNED NOT NULL,
`name` CHAR(50) NOT NULL COLLATE 'utf8_unicode_ci',
`group` INT(10) UNSIGNED NOT NULL, `group` INT(10) UNSIGNED NOT NULL,
`id` CHAR(50) NOT NULL, `state` CHAR(50) NOT NULL COLLATE 'utf8_unicode_ci',
`div` CHAR(50) NOT NULL, `parent_id` INT(10) UNSIGNED NOT NULL,
`url` TEXT NOT NULL, `type` INT(10) UNSIGNED NOT NULL DEFAULT '0',
`func` CHAR(50) NOT NULL, `div` CHAR(50) NOT NULL COLLATE 'utf8_unicode_ci',
`php_class` CHAR(50) NOT NULL, `url` TEXT NOT NULL COLLATE 'utf8_unicode_ci',
PRIMARY KEY (`id`, `div`, `group`) `func` CHAR(50) NOT NULL COLLATE 'utf8_unicode_ci',
`php_class` CHAR(50) NOT NULL COLLATE 'utf8_unicode_ci',
PRIMARY KEY (`id`, `group`, `state`, `name`)
) )
COLLATE='utf8_unicode_ci' COLLATE='utf8_unicode_ci'
ENGINE=InnoDB; ENGINE=InnoDB
;

View File

@ -5,8 +5,12 @@ class system_page {
const NAME_PG = 'system.page'; const NAME_PG = 'system.page';
const NAME_MYS = 'system_page'; const NAME_MYS = 'system_page';
const FIELD_GROUP = 'group';
const FIELD_ID = 'id'; const FIELD_ID = 'id';
const FIELD_NAME = 'name';
const FIELD_GROUP = 'group';
const FIELD_STATE = 'state';
const FIELD_PARENT_ID = 'parent_id';
const FIELD_TYPE = 'type';
const FIELD_DIV = 'div'; const FIELD_DIV = 'div';
const FIELD_URL = 'url'; const FIELD_URL = 'url';
const FIELD_FUNC = 'func'; const FIELD_FUNC = 'func';

View File

@ -28,6 +28,9 @@ class files {
}else{ }else{
\SYSTEM\HEADER::FILE($id);} \SYSTEM\HEADER::FILE($id);}
//Allow Caching for all files
header('Cache-Control: public;');
if(!self::file_get_contents_chunked(self::$folders[$cat].$id,4096,function($chunk,&$handle,$iteration){echo $chunk;})){ if(!self::file_get_contents_chunked(self::$folders[$cat].$id,4096,function($chunk,&$handle,$iteration){echo $chunk;})){
throw new \SYSTEM\LOG\ERROR("Could not transfere File.");} throw new \SYSTEM\LOG\ERROR("Could not transfere File.");}
return; return;

View File

@ -10,13 +10,13 @@ function SYSTEM(endpoint,group,start_state,hash_change){
this.endpoint = endpoint; this.endpoint = endpoint;
this.group = group; this.group = group;
this.pages = null; this.start_state = start_state;
this.hash_change = hash_change;
this.state = {}; this.state = {};
this.state_info = {}; this.state_info = {};
this.state_js = {}; this.state_js = {};
this.state_css = {}; this.state_css = {};
this.start_state = start_state;
this.hash_change = hash_change;
this.hashchange(); this.hashchange();
$(window).bind('hashchange', this.hashchange); $(window).bind('hashchange', this.hashchange);
@ -25,70 +25,66 @@ SYSTEM.prototype.hashchange = function () {
system.go_state(system.start_state); system.go_state(system.start_state);
//user callback //user callback
if(system.hash_change){ if(system.hash_change){
system.hash_change(system.cur_state());} system.hash_change(system.cur_state().split('(')[0]);}
}; };
SYSTEM.prototype.handle_call_pages_data = function (entry,id,forced,cached) { SYSTEM.prototype.handle_call_pages_page = function (html,entry,id,forced,cached) {
var url = entry['url']+(window.location.search.substr(1) ? '&'+window.location.search.substr(1) : '' ); var url = entry['url']+(window.location.search.substr(1) ? '&'+window.location.search.substr(1) : '' );
//check loaded state of div - reload only if required if($(entry['div']).length){
if(forced || this.state[entry['div']] !== url){ $(entry['div']).html(html);
//load pages this.log_info('load page: '+id+entry['div']+' '+url+' - success');
$.ajax({ } else {
async: false, this.log_error('load page: '+id+entry['div']+' '+url+' - div not found');
data: {}, }
dataType: 'html', //load css
url: url, for(var i=0; i < entry['css'].length; i++){
success: function(data){ this.load_css(entry['css'][i],forced);}
if($(entry['div']).length){ //load js
$(entry['div']).html(data); var call_func = true;
system.log_info('load page: '+id+entry['div']+' '+url+' - success'); var loaded = 0;
} else { for(var i=0; i < entry['js'].length; i++){
system.log_error('load page: '+id+entry['div']+' '+url+' - div not found'); if(forced || !this.state_js[entry['js'][i]]){
}}, this.log_info('load js: '+entry['js'][i]+(forced ? ' - forced' : ''));
error: function(XMLHttpRequest, textStatus, errorThrown){system.log_error(errorThrown);} $.getScript(entry['js'][i])
}); .done(function(response, status, jqxhr) {
//load css system.log_info('load js: '+status);
for(var i=0; i < entry['css'].length; i++){ if(loaded++ === entry['js'].length-1){
this.load_css(entry['css'][i],forced);} var fn = window[entry['func']];
//load js if(call_func && typeof fn === 'function'){
var call_func = true; call_func = false;
var loaded = 0; fn();
for(var i=0; i < entry['js'].length; i++){ system.log_info('call func: '+entry['func']);
if(forced || !this.state_js[entry['js'][i]]){ } else {
this.log_info('load js: '+entry['js'][i]+(forced ? ' - forced' : '')); system.log_error('call func: '+entry['func']+' - fail');
$.getScript(entry['js'][i])
.done(function(response, status, jqxhr) {
system.log_info('load js: '+status);
if(loaded++ === entry['js'].length-1){
var fn = window[entry['func']];
if(call_func && typeof fn === 'function'){
call_func = false;
fn();
system.log_info('call func: '+entry['func']);
} else {
system.log_error('call func: '+entry['func']+' - fail');
}
} }
})
.fail(function( jqxhr, settings, exception ) {
system.log_error( "Something went wrong"+exception );
});
this.state_js[entry['js'][i]] = true;
} else {
this.log_info('load js: '+entry['js'][i]+' - cached');
if(loaded++ === entry['js'].length-1){
var fn = window[entry['func']];
if(call_func && typeof fn === 'function'){
call_func = false;
fn();
this.log_info('call func: '+entry['func']);
} else {
this.log_error('call func: '+entry['func']+' - fail');
} }
})
.fail(function( jqxhr, settings, exception ) {
system.log_error( "Something went wrong"+exception );
});
this.state_js[entry['js'][i]] = true;
} else {
this.log_info('load js: '+entry['js'][i]+' - cached');
if(loaded++ === entry['js'].length-1){
var fn = window[entry['func']];
if(call_func && typeof fn === 'function'){
call_func = false;
fn();
this.log_info('call func: '+entry['func']);
} else {
this.log_error('call func: '+entry['func']+' - fail');
} }
} }
} }
//update state }
this.state[entry['div']] = url; //update state
this.state[entry['div']] = url;
}
SYSTEM.prototype.handle_call_pages_entry = function (entry,id,forced,cached) {
var url = entry['url']+(window.location.search.substr(1) ? '&'+window.location.search.substr(1) : '' );
//check loaded state of div - reload only if required
if(forced || this.state[entry['div']] !== url){
//load page
this.call_url(url,function(data){system.handle_call_pages_page(data,entry,id,forced,cached);},{},'html',true);
} else { } else {
this.log_info('load page: '+id+entry['div']+' '+url+' - skipped - already loaded'); this.log_info('load page: '+id+entry['div']+' '+url+' - skipped - already loaded');
} }
@ -96,6 +92,10 @@ SYSTEM.prototype.handle_call_pages_data = function (entry,id,forced,cached) {
//internal function to handle pagestate results //internal function to handle pagestate results
SYSTEM.prototype.handle_call_pages = function (data,id,forced,cached) { SYSTEM.prototype.handle_call_pages = function (data,id,forced,cached) {
if(data['status']){ if(data['status']){
//clear old state
this.state = {}
this.state_info = {}
this.log_info('load pages: endpoint '+this.endpoint+' group:'+this.group+' state:'+id+' - '+(cached ? 'cached ' : (forced ? 'forced' : 'success'))); this.log_info('load pages: endpoint '+this.endpoint+' group:'+this.group+' state:'+id+' - '+(cached ? 'cached ' : (forced ? 'forced' : 'success')));
//state not found? //state not found?
if(data['result'].length === 0){ if(data['result'].length === 0){
@ -108,18 +108,21 @@ SYSTEM.prototype.handle_call_pages = function (data,id,forced,cached) {
if(id !== this.cur_state()){ if(id !== this.cur_state()){
window.history.pushState(null, "", '#!'+id);} window.history.pushState(null, "", '#!'+id);}
data['result'].forEach( data['result'].forEach(
function(entry) { system.handle_call_pages_data(entry,id,forced,cached);}); function(entry) { system.handle_call_pages_entry(entry,id,forced,cached);});
} else { } else {
this.log_info('Problem with your Pages: '+data['result']['message']); this.log_info('Problem with your Pages: '+data['result']['message']);
} }
}; };
//send a call to the endpoint //send a call to the endpoint
SYSTEM.prototype.call = function(call,success,data,data_type,async){ SYSTEM.prototype.call = function(call,success,data,data_type,async){
this.call_url(this.endpoint+'?'+call,success,data,data_type,async);
};
SYSTEM.prototype.call_url = function(url,success,data,data_type,async){
$.ajax({ $.ajax({
async: async, async: async,
data: data, data: data,
dataType: data_type, dataType: data_type,
url: this.endpoint+'?'+call, url: url,
success: success, success: success,
error: function(XMLHttpRequest, textStatus, errorThrown){system.log_error(call+' '+XMLHttpRequest+' '+textStatus+' '+errorThrown);} error: function(XMLHttpRequest, textStatus, errorThrown){system.log_error(call+' '+XMLHttpRequest+' '+textStatus+' '+errorThrown);}
}); });

View File

@ -2,14 +2,23 @@
namespace SYSTEM\PAGE; namespace SYSTEM\PAGE;
class State { class State {
public static function get($group,$state,$returnasjson=true){ public static function get($group,$state,$returnasjson=true){
$state = \explode(';', $state); //seperate state from vars
$state_vars = \explode(';', $state);
//parse substates
$state_all = \explode('(', $state_vars[0]);
$state_name = $state_all[0];
$substate = substr($state_vars[0], strlen($state_name));
$substate = self::parse_substate($substate);
//vars
$vars = array(); $vars = array();
for($i=1;$i<count($state);$i++){ for($i=1;$i<count($state);$i++){
$var = \explode('.',$state[$i]); $var = \explode('.',$state[$i]);
$vars[$var[0]] = $var[1];} $vars[$var[0]] = $var[1];}
$result = array(); $result = array();
$res = \SYSTEM\DBD\SYS_PAGE_GROUP::QQ(array($group,$state[0])); $res = \SYSTEM\DBD\SYS_PAGE_GROUP::QQ(array($group,$state_name));
while($row = $res->next()){ while($row = $res->next()){
if(!self::is_loaded($row,$substate,$state_name) && $row['type'] == 1){
continue;}
$row['url'] = \SYSTEM\PAGE\replace::replace($row['url'], $vars); $row['url'] = \SYSTEM\PAGE\replace::replace($row['url'], $vars);
$row['url'] = \SYSTEM\PAGE\replace::clean($row['url']); $row['url'] = \SYSTEM\PAGE\replace::clean($row['url']);
//clean url of empty variables //clean url of empty variables
@ -23,5 +32,104 @@ class State {
$row['php_class'] = ''; $row['php_class'] = '';
$result[] = $row; $result[] = $row;
} }
return $returnasjson ? \SYSTEM\LOG\JsonResult::toString($result) : $result;} return $returnasjson ? \SYSTEM\LOG\JsonResult::toString($result) : $result;
}
public static function parse_substate($substate){
return (new ParensParser())->parse($substate);
}
private static function is_loaded($row,&$substate,$state_name,$parent_id = -1){
for($i=0;$i<count($substate);$i++){
if($row['name'] == $state_name){
$substate[$i]['parent_id'] = $row['id'];}
if($substate[$i]['name'] == $row['name'] && $substate[$i]['parent_id'] == $row['parent_id']){
$substate[$i]['parent_id'] = $parent_id;
return true;
}
if(array_key_exists('parent_id', $substate[$i])){
if(self::is_loaded($row,$substate[$i]['sub'],$state_name,$substate[$i]['parent_id'])){
return true;}
}
}
return false;
}
}
class ParensParser
{
// something to keep track of parens nesting
protected $stack = null;
// current level
protected $current = null;
// input string to parse
protected $string = null;
// current character offset in string
protected $position = null;
// start of text-buffer
protected $buffer_start = null;
public function parse($string)
{
if (!$string) {
// no string, no data
return array();
}
if ($string[0] == '(') {
// killer outer parens, as they're unnecessary
$string = substr($string, 1, -1);
}
$this->current = array();
$this->stack = array();
$this->string = $string;
$this->length = strlen($this->string);
// look at each character
for ($this->position=0; $this->position < $this->length; $this->position++) {
switch ($this->string[$this->position]) {
case '(':
$this->push();
// push current scope to the stack an begin a new scope
array_push($this->stack, $this->current);
$this->current = array();
break;
case ')':
$this->push();
// save current scope
$t = $this->current;
// get the last scope from stack
$this->current = array_pop($this->stack);
// add just saved scope to current scope
$this->current[count($this->current)-1]['sub'] = $t;
break;
case '|':
// make each word its own token
$this->push();
break;
default:
// remember the offset to do a string capture later
// could've also done $buffer .= $string[$position]
// but that would just be wasting resources…
if ($this->buffer_start === null) {
$this->buffer_start = $this->position;
}
}
}
$this->push();
return $this->current;
}
protected function push()
{
if ($this->buffer_start !== null) {
// extract string from buffer start to current position
$buffer = substr($this->string, $this->buffer_start, $this->position - $this->buffer_start);
// clean buffer
$this->buffer_start = null;
// throw token into current scope
$this->current[] = array('name' => $buffer);
}
}
} }

View File

@ -1 +1 @@
<a href="javascript:system.language('${lang}');"><img src="./api.php?call=files&amp;cat=saistart_sys_sai&amp;id=flag_${lang}.png" alt="${lang}"></a>&nbsp; <a href="javascript:system.language('${lang}');"><img src="./api.php?call=files&amp;cat=saistart_sys_sai&amp;id=flag_${lang}.png" alt="${lang}" width="16" height="11"></a>&nbsp;

View File

@ -298,7 +298,8 @@ class saimod_sys_log extends \SYSTEM\SAI\SaiModule {
//print_r($r); //print_r($r);
$r['class_row'] = self::tablerow_class($r['class']); $r['class_row'] = self::tablerow_class($r['class']);
$r['time'] = self::time_elapsed_string(strtotime($r['time'])); $r['time'] = self::time_elapsed_string(strtotime($r['time']));
$r['message'] = substr($r['message'],0,255); $r['message'] = htmlspecialchars(substr($r['message'],0,255));
$r['request_uri'] = htmlspecialchars($r['request_uri']);
$table .= \SYSTEM\PAGE\replace::replaceFile(\SYSTEM\SERVERPATH(new \SYSTEM\PSAI(),'modules/saimod_sys_log/tpl/saimod_sys_log_table_row.tpl'),$r); $table .= \SYSTEM\PAGE\replace::replaceFile(\SYSTEM\SERVERPATH(new \SYSTEM\PSAI(),'modules/saimod_sys_log/tpl/saimod_sys_log_table_row.tpl'),$r);
} }
$vars = array(); $vars = array();

View File

@ -47,6 +47,8 @@ class saimod_sys_todo extends \SYSTEM\SAI\SaiModule {
//$row['report_type'] = self::reporttype($row['type']); //$row['report_type'] = self::reporttype($row['type']);
$row['state_string'] = self::state($row['count']); $row['state_string'] = self::state($row['count']);
$row['state_btn'] = self::statebtn($row['count']); $row['state_btn'] = self::statebtn($row['count']);
$row['message'] = htmlspecialchars($row['message']);
$row['request_uri'] = htmlspecialchars($row['request_uri']);
if($row['type'] == \SYSTEM\DBD\system_todo::FIELD_TYPE_USER){ if($row['type'] == \SYSTEM\DBD\system_todo::FIELD_TYPE_USER){
$row['message'] = str_replace("\r", '<br/>', $row['message']); $row['message'] = str_replace("\r", '<br/>', $row['message']);
$result_user .= \SYSTEM\PAGE\replace::replaceFile(\SYSTEM\SERVERPATH(new \SYSTEM\PSAI(),'modules/saimod_sys_todo/tpl/todo_user_list_element.tpl'), $row); $result_user .= \SYSTEM\PAGE\replace::replaceFile(\SYSTEM\SERVERPATH(new \SYSTEM\PSAI(),'modules/saimod_sys_todo/tpl/todo_user_list_element.tpl'), $row);

View File

@ -29,8 +29,6 @@ class saistart_sys_sai extends \SYSTEM\SAI\SaiModule {
$vars = array(); $vars = array();
$vars['project_name'] = \SYSTEM\CONFIG\config::get(\SYSTEM\CONFIG\config_ids::SYS_SAI_CONFIG_PROJECT); $vars['project_name'] = \SYSTEM\CONFIG\config::get(\SYSTEM\CONFIG\config_ids::SYS_SAI_CONFIG_PROJECT);
$vars['project_url'] = \SYSTEM\CONFIG\config::get(\SYSTEM\CONFIG\config_ids::SYS_CONFIG_PATH_BASEURL); $vars['project_url'] = \SYSTEM\CONFIG\config::get(\SYSTEM\CONFIG\config_ids::SYS_CONFIG_PATH_BASEURL);
$vars['todo_entries'] = \SYSTEM\SAI\saimod_sys_todo::sai_mod__SYSTEM_SAI_saimod_sys_todo_action_todolist();
$vars['log_entries'] = \SYSTEM\SAI\saimod_sys_log::sai_mod__SYSTEM_SAI_saimod_sys_log_action_filter();
$vars['analytics'] = \SYSTEM\SAI\saimod_sys_log::analytics(); $vars['analytics'] = \SYSTEM\SAI\saimod_sys_log::analytics();
$user = \SYSTEM\SECURITY\Security::getUser(); $user = \SYSTEM\SECURITY\Security::getUser();
$vars['username'] = $user->username; $vars['username'] = $user->username;

View File

@ -48,10 +48,10 @@
<h2 class="muted"><a href="#!todo">Todo</a></h2> <h2 class="muted"><a href="#!todo">Todo</a></h2>
<b>Status:</b> ${project_count}/${project_all}<br/> <b>Status:</b> ${project_count}/${project_all}<br/>
<b>Progress:</b> ${project}% <b>Progress:</b> ${project}%
${todo_entries} <div id="todo_entries"></div>
</div> </div>
<div class="well" id="log"> <div class="well" id="log">
<h2 class="muted"><a href="#!log">Log</a></h2> <h2 class="muted"><a href="#!log">Log</a></h2>
<h4 class="muted">100 Latest Log Entries</h4> <h4 class="muted">100 Latest Log Entries</h4>
${log_entries} <div id="log_entries"></div>
</div> </div>