Skip to content

Commit

Permalink
Ticket unacms#363 - base functionality.
Browse files Browse the repository at this point in the history
  • Loading branch information
AntonLV committed Jun 5, 2017
1 parent d55d10e commit 8fdc2a4
Show file tree
Hide file tree
Showing 19 changed files with 766 additions and 3 deletions.
34 changes: 34 additions & 0 deletions chart.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
<?php
/**
* Copyright (c) UNA, Inc - https://una.io
* MIT License - https://opensource.org/licenses/MIT
*
* @defgroup UnaCore UNA Core
* @{
*/

require_once('./inc/header.inc.php');
require_once(BX_DIRECTORY_PATH_INC . "design.inc.php");

bx_import('BxDolLanguages');

check_logged();

$sObject = isset($_REQUEST['object']) ? bx_process_input($_REQUEST['object']) : '';
$sAction = isset($_REQUEST['action']) && preg_match ('/^[A-Za-z_-]+$/', $_REQUEST['action']) ? bx_process_input($_REQUEST['action']) : '';

$oChart = BxDolChart::getObjectInstance($sObject);
if(!$oChart || !$sAction) {
echoJson(array());
exit;
}

$sMethod = 'action' . bx_gen_method_name($sAction);
if(!method_exists($oChart, $sMethod)) {
echoJson(array());
exit;
}

$oChart->$sMethod();

/** @} */
164 changes: 164 additions & 0 deletions inc/classes/BxDolChart.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
<?php defined('BX_DOL') or die('hack attempt');
/**
* Copyright (c) UNA, Inc - https://una.io
* MIT License - https://opensource.org/licenses/MIT
*
* @defgroup UnaCore UNA Core
* @{
*/


class BxDolChart extends BxDolFactory implements iBxDolFactoryObject
{
protected $_oDb;
protected $_sObject;
protected $_aObject;

/**
* Constructor
* @param $aObject array of chart options
*/
protected function __construct($aObject)
{
parent::__construct();

$this->_oDb = new BxDolChartQuery($this->_aObject);

$this->_sObject = $aObject['object'];
$this->_aObject = $aObject;
}

/**
* Get editor object instance by object name
* @param $sObject object name
* @return object instance or false on error
*/
static public function getObjectInstance($sObject = false, $oTemplate = false)
{
if(isset($GLOBALS['bxDolClasses']['BxDolChart!' . $sObject]))
return $GLOBALS['bxDolClasses']['BxDolChart!' . $sObject];

$aObject = BxDolChartQuery::getChartObject($sObject);
if(!$aObject || !is_array($aObject))
return false;

$sClass = 'BxTemplChart';
if(!empty($aObject['class_name'])) {
$sClass = $aObject['class_name'];
if(!empty($aObject['class_file']))
require_once(BX_DIRECTORY_PATH_ROOT . $aObject['class_file']);
}

$o = new $sClass($aObject, $oTemplate);
return ($GLOBALS['bxDolClasses']['BxDolChart!' . $sObject] = $o);
}

public function actionLoadDataByInterval()
{
$mixedResult = $this->checkAllowedView();
if($mixedResult !== CHECK_ACTION_RESULT_ALLOWED)
return array('error' => $mixedResult);

$iFrom = $this->_getTimestamp(bx_get('from'));
$iTo = $this->_getTimestamp(bx_get('to'), true);
if(!$iFrom || !$iTo)
return echoJson(array('error' => _t('_Error Occured')));

$aData = $this->getDataByInterval($iFrom, $iTo);
if(empty($aData) || !is_array($aData))
return echoJson(array('error' => _t('_Empty')));

return echoJson(array (
'title' => _t($this->_aObject['title']),
'data' => $aData,
'hide_date_range' => $this->_aObject['field_date_dt'] || $this->_aObject['field_date_ts'] ? false : true,
'column_date' => $this->_aObject['column_date'] >= 0 ? $this->_aObject['column_date'] : false,
'column_count' => $this->_aObject['column_count'] >= 0 ? $this->_aObject['column_count'] : false,
'type' => $this->_aObject['type'] ? $this->_aObject['type'] : 'AreaChart',
'options' => $this->_aObject['options'] ? unserialize($this->_aObject['options']) : false,
));
}

public function checkAllowedView($isPerformAction = false)
{
return BxDolService::call('system', 'check_allowed_view', array($isPerformAction), 'TemplChartServices');
}

public function getDataByInterval($iFrom, $iTo)
{
// build query
$sQuery = $this->_aObject['query'] ? $this->_aObject['query'] : "SELECT {field_date_formatted} AS `period`, COUNT(*) AS {object} FROM {table} WHERE {field_date} >= :from AND {field_date} <= :to GROUP BY `period` ORDER BY {field_date} ASC";
$sQuery = bx_replace_markers($sQuery, array (
'field_date_formatted' => "DATE_FORMAT(" . ($this->_aObject['field_date_dt'] ? "`{$this->_aObject['field_date_dt']}`" : "FROM_UNIXTIME(`{$this->_aObject['field_date_ts']}`)") . ", '%Y-%m-%d')",
'object' => $this->_aObject['object'],
'table' => "`{$this->_aObject['table']}`",
'field_date' => "`" . ($this->_aObject['field_date_dt'] ? $this->_aObject['field_date_dt'] : $this->_aObject['field_date_ts']) . "`",
));

$aBindings = array(
'from' => $this->_aObject['field_date_dt'] ? $this->_getDate($iFrom) . ' 00:00:00' : $iFrom,
'to' => $this->_aObject['field_date_dt'] ? $this->_getDate($iTo) . ' 23:59:59' : $iTo + 24*3600 - 1,
);

// get data
if ($this->_aObject['column_date'] >= 0)
$aData = $this->_oDb->getAllWithKey($sQuery, $this->_aObject['column_date'], $aBindings, PDO::FETCH_NUM);
else
$aData = $this->_oDb->getAll($sQuery, array(), $aBindings, PDO::FETCH_NUM);

if (!$aData)
return false;

// fill in missed days and convert values to numbers
if ($this->_aObject['column_date'] >= 0) {
$aDataSlice = array_slice($aData, 0, 1);
$iColumnsNum = count(array_pop($aDataSlice));
for ($i = $iFrom ; $i <= ($iTo + 24*3600 - 1); $i += 24*60*60) {
$sDate = $this->_getDate($i);
$aRow = array ();
for ($j = 0 ; $j < $iColumnsNum ; ++$j) {
$v = isset($aData[$sDate]) ? (int)$aData[$sDate][$j] : 0;
$aRow[$j] = ($j == $this->_aObject['column_date'] ? $sDate : $v);
}
$aData[$sDate] = $aRow;
}
}
else
foreach ($aData as $k => $v)
foreach ($aData[$k] as $kk => $vv)
if ($kk > 0)
$aData[$k][$kk] = (int)$aData[$k][$kk];

// return values only
ksort($aData);
return array_values($aData);
}

public function getDataByStatus()
{
// build query
$sQuery = $this->_aObject['query'] ? $this->_aObject['query'] : "SELECT COUNT(*) AS {object} FROM {table} WHERE 1" . (!empty($this->_aObject['query_status']) ? $this->_aObject['query_status'] : '');
$sQuery = bx_replace_markers($sQuery, array (
'object' => $this->_aObject['object'],
'table' => "`{$this->_aObject['table']}`",
));

return $this->_oDb->getOne($sQuery);
}

protected function _getTimestamp($sDate, $isNowIfError = false)
{
$aDate = explode('-', $sDate); // YYYY-MM-DD
if(!$aDate || empty($aDate[0]) || empty($aDate[1]) || empty($aDate[2]) || !(int)$aDate[0] || !(int)$aDate[1] || !(int)$aDate[2])
return $isNowIfError ? time() : false;

return mktime(0, 0, 0, $aDate[1], $aDate[2], $aDate[0]);
}

protected function _getDate($iDate)
{
return date('Y-m-d', $iDate);
}
}

/** @} */
42 changes: 42 additions & 0 deletions inc/classes/BxDolChartQuery.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php defined('BX_DOL') or die('hack attempt');
/**
* Copyright (c) UNA, Inc - https://una.io
* MIT License - https://opensource.org/licenses/MIT
*
* @defgroup UnaCore UNA Core
* @{
*/

class BxDolChartQuery extends BxDolDb
{
public function __construct($aObject = array())
{
parent::__construct();
}

static public function getChartObject($sObject)
{
$oDb = BxDolDb::getInstance();

$sQuery = $oDb->prepare("SELECT * FROM `sys_objects_chart` WHERE `object` = ?", $sObject);

$aObject = $oDb->getRow($sQuery);
if(!$aObject || !is_array($aObject))
return false;

return $aObject;
}

static public function getChartObjects()
{
$oDb = BxDolDb::getInstance();

$aObjects = $oDb->getAll("SELECT * FROM `sys_objects_chart` WHERE `active` = '1' ORDER BY `order` ASC");
if(!$aObjects || !is_array($aObjects))
return false;

return $aObjects;
}
}

/** @} */
109 changes: 109 additions & 0 deletions inc/js/classes/BxDolChartGrowth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/**
* Copyright (c) UNA, Inc - https://una.io
* MIT License - https://opensource.org/licenses/MIT
*
* @defgroup UnaCore UNA Core
* @{
*/

function BxDolChartGrowth (oOptions) {
this._sObjName = undefined == oOptions.sObjName ? 'oBxDolChartGrowth' : oOptions.sObjName; // javascript object name, to run current object instance from onTimer
this._sActionsUrl = oOptions.sRootUrl + 'chart.php'; // actions url address

this._sAnimationEffect = 'fade';
this._iAnimationSpeed = 'slow';

this._sKeyObjects = 'bx_chart_growth_objects';
this._sKeyDateFrom = 'bx_chart_growth_date_from';
this._sKeyDateTo = 'bx_chart_growth_date_to';
this._sKeyGraph = 'bx_chart_growth_graph';

this._sDateFormat = 'yy-mm-dd';

var $this = this;
$(document).ready(function() {
google.setOnLoadCallback($this.loadData());
});
}

BxDolChartGrowth.prototype.loadData = function()
{
var $this = this;


$('#' + this._sKeyGraph).html('');
$('#' + this._sKeyObjects).attr('disabled', true);

bx_loading(this._sKeyGraph, true);

$.get(
this._sActionsUrl,
{
object: $('#' + this._sKeyObjects).val(),
action: 'load_data_by_interval',
from: $.datepicker.formatDate($this._sDateFormat, $('#' + $this._sKeyDateFrom).datepicker('getDate')),
to: $.datepicker.formatDate($this._sDateFormat, $('#' + $this._sKeyDateTo).datepicker('getDate'))
},
function(oData) {
$('#' + $this._sKeyObjects).attr('disabled', false);

bx_loading($this._sKeyGraph, false);

if(oData.error != undefined) {
$('#' + $this._sKeyGraph).html('<div class="bx-def-padding bx-def-font-large bx-def-font-align-center">' + oData.error + '</div>');
return;
}

// hide date selector if chart doesn't support date range
if (oData.hide_date_range) {
$('#' + $this._sKeyDateFrom).parents('.bx-form-element-wrapper:first').fadeOut();
$('#' + $this._sKeyDateTo).parents('.bx-form-element-wrapper:first').fadeOut();
}
else {
$('#' + $this._sKeyDateFrom).parents('.bx-form-element-wrapper:first').fadeIn();
$('#' + $this._sKeyDateTo).parents('.bx-form-element-wrapper:first').fadeIn();
}

// convert dates
if(oData.column_date !== false) {
for (var i in oData.data) {
var sDate = oData.data[i][oData.column_date];
var m = sDate.match(/(\d{4})-(\d{2})-(\d{2})/);
if(!m || !m[1] || !m[2] || !m[3])
continue;

var oDate = new Date(m[1],m[2]-1,m[3]);
oData.data[i][oData.column_date] = oDate;
}
}

// add data
var oDataTable = new google.visualization.DataTable();
for (var i = 0 ; i < oData.data[0].length ; ++i) {
var sType = 0 == i ? 'string' : 'number';
var sLabel = '';
if (false !== oData.column_date && i == oData.column_date)
sType = 'datetime';
else if (false !== oData.column_count && i == oData.column_count)
sLabel = oData.title;
oDataTable.addColumn(sType, sLabel);
}
oDataTable.addRows(oData.data);

// define options
var oOptions = {
title: oData.title
};

if (oData.options != undefined)
oOptions = jQuery.extend(oOptions, oData.options);

// draw chart
var chart = new google.visualization[oData.type]($('#' + $this._sKeyGraph)[0]);
chart.draw(oDataTable, oOptions);
},
'json'
);
};

/** @} */
Loading

0 comments on commit 8fdc2a4

Please sign in to comment.