Version 4.6.0
This commit is contained in:
1 parent
f79dcf067a
commit
517a5e1f70
2036 files changed
+110041
-26162
No files matched your search
@@ -28,6 +28,11 @@ class _Callback extends \IPS\Helpers\Chart\Dynamic
|
||||
* @brief Callback to retrieve results
|
||||
*/
|
||||
public $callback;
|
||||
|
||||
/**
|
||||
* @brief Custom form
|
||||
*/
|
||||
public $customFiltersForm = FALSE;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -103,7 +108,7 @@ class _Callback extends \IPS\Helpers\Chart\Dynamic
|
||||
* @param array $data The data
|
||||
* @return void
|
||||
*/
|
||||
public function compileForOutput(): void
|
||||
public function compileForOutput()
|
||||
{
|
||||
/* Init data */
|
||||
$data = $this->initData();
|
||||
|
||||
@@ -93,24 +93,26 @@ class _Chart
|
||||
$values = array_values( $values );
|
||||
foreach ( $this->headers as $data )
|
||||
{
|
||||
$value = \is_array( $values[ $i ] ) ? $values[ $i ]['value'] : $values[ $i ];
|
||||
|
||||
switch ( $data['type'] )
|
||||
{
|
||||
case 'string':
|
||||
if ( !\is_string( $values[ $i ] ) )
|
||||
if ( !\is_string( $value ) )
|
||||
{
|
||||
throw new \InvalidArgumentException( "VALUE_{$i}_NOT_STRING" );
|
||||
}
|
||||
break;
|
||||
|
||||
case 'number':
|
||||
if ( !\is_numeric( $values[ $i ] ) and !\is_null( $values[ $i ] ) )
|
||||
if ( !\is_numeric( $value ) and !\is_null( $value ) )
|
||||
{
|
||||
throw new \InvalidArgumentException( "VALUE_{$i}_NOT_NUMBER" );
|
||||
}
|
||||
break;
|
||||
|
||||
case 'bool':
|
||||
if ( !\is_bool( $values[ $i ] ) )
|
||||
if ( !\is_bool( $value ) )
|
||||
{
|
||||
throw new \InvalidArgumentException( "VALUE_{$i}_NOT_BOOL" );
|
||||
}
|
||||
@@ -119,12 +121,19 @@ class _Chart
|
||||
case 'date':
|
||||
case 'datetime':
|
||||
case 'timeofday':
|
||||
if ( !( $values[ $i ] instanceof \IPS\DateTime ) )
|
||||
if ( !( $value instanceof \IPS\DateTime ) )
|
||||
{
|
||||
throw new \InvalidArgumentException( "VALUE_{$i}_NOT_DATETIME" );
|
||||
}
|
||||
|
||||
$values[ $i ] = $values[ $i ]->rfc3339();
|
||||
|
||||
if ( \is_array( $values[ $i ] ) )
|
||||
{
|
||||
$values[ $i ]['value'] = $value->rfc3339();
|
||||
}
|
||||
else
|
||||
{
|
||||
$values[ $i ] = $value->rfc3339();
|
||||
}
|
||||
break;
|
||||
}
|
||||
$i++;
|
||||
|
||||
@@ -61,7 +61,12 @@ class _Database extends \IPS\Helpers\Chart\Dynamic
|
||||
* @brief Table Column Formatters
|
||||
*/
|
||||
public $tableParsers = array();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Custom form
|
||||
*/
|
||||
public $customFiltersForm = FALSE;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
@@ -96,7 +101,7 @@ class _Database extends \IPS\Helpers\Chart\Dynamic
|
||||
/**
|
||||
* Add Series
|
||||
*
|
||||
* @param string $name Name
|
||||
* @param mixed $name Either a string with the series name or an array [ 'value' => "Series Name", 'key' => "XX" ]. Keys are used to give a country code for GeoCharts.
|
||||
* @param string $type Type of value
|
||||
* @li string
|
||||
* @li number
|
||||
@@ -117,6 +122,7 @@ class _Database extends \IPS\Helpers\Chart\Dynamic
|
||||
}
|
||||
else
|
||||
{
|
||||
$name = \is_array( $name ) ? $name['value'] : $name;
|
||||
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $name );
|
||||
$filterKey = $name;
|
||||
}
|
||||
@@ -125,7 +131,7 @@ class _Database extends \IPS\Helpers\Chart\Dynamic
|
||||
{
|
||||
if ( $this->type !== 'PieChart' and $this->type !== 'GeoChart' )
|
||||
{
|
||||
$this->addHeader( $name, $type );
|
||||
$this->addHeader( \is_array( $name ) ? $name['value'] : $name, $type );
|
||||
}
|
||||
|
||||
if( $this->groupBy )
|
||||
@@ -152,17 +158,75 @@ class _Database extends \IPS\Helpers\Chart\Dynamic
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Init the data array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function initData()
|
||||
{
|
||||
$data = parent::initData();
|
||||
|
||||
if ( $this->customFiltersForm )
|
||||
{
|
||||
if ( $values = $this->getCustomFiltersForm()->values() )
|
||||
{
|
||||
$whereFunction = $this->customFiltersForm['where'];
|
||||
$seriesFunction = $this->customFiltersForm['series'];
|
||||
|
||||
foreach( $values as $k => $v )
|
||||
{
|
||||
unset( $values[ $k ] );
|
||||
$values[ \mb_substr( $k, \mb_strlen( $this->identifier ) ) ] = $v;
|
||||
}
|
||||
|
||||
$this->groupBy = $this->customFiltersForm['groupBy'];
|
||||
$this->where = array( array( $whereFunction( $values ) ) );
|
||||
|
||||
foreach( $seriesFunction( $values ) as $series )
|
||||
{
|
||||
$this->addSeries( $series[0], $series[1], $series[2], $series[3], $series[4] );
|
||||
}
|
||||
}
|
||||
else if ( $this->savedCustomFilters and \count( $this->savedCustomFilters ) )
|
||||
{
|
||||
$whereFunction = $this->customFiltersForm['where'];
|
||||
$seriesFunction = $this->customFiltersForm['series'];
|
||||
|
||||
$this->groupBy = $this->customFiltersForm['groupBy'];
|
||||
$this->where = array( array( $whereFunction( $this->savedCustomFilters ) ) );
|
||||
|
||||
foreach( $seriesFunction( $this->savedCustomFilters ) as $series )
|
||||
{
|
||||
$this->addSeries( $series[0], $series[1], $series[2], $series[3], $series[4] );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$seriesFunction = $this->customFiltersForm['defaultSeries'];
|
||||
|
||||
foreach( $seriesFunction() as $series )
|
||||
{
|
||||
$this->addSeries( $series[0], $series[1], $series[2], $series[3], $series[4] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile Data for Output
|
||||
*
|
||||
* @param array $data The data
|
||||
* @return void
|
||||
*/
|
||||
public function compileForOutput(): void
|
||||
public function compileForOutput()
|
||||
{
|
||||
/* Init data */
|
||||
$data = $this->initData();
|
||||
|
||||
|
||||
/* Work out where clause */
|
||||
$where = $this->where;
|
||||
$where[] = array( "{$this->dateField}>?", 0 );
|
||||
@@ -237,8 +301,9 @@ class _Database extends \IPS\Helpers\Chart\Dynamic
|
||||
{
|
||||
$fromUnixTime = "CONVERT_TZ( {$fromUnixTime}, @@session.time_zone, '" . \IPS\Db::i()->escape_string( \IPS\Member::loggedIn()->timezone ) . "' )";
|
||||
}
|
||||
|
||||
$stmt = \IPS\Db::i()->select(
|
||||
"DATE_FORMAT( {$fromUnixTime}, '{$timescale}' ) AS time_as_alias, " . implode( ', ', array_unique( $this->series ) ) . ( $this->groupBy ? ", " . $this->groupBy : '' ),
|
||||
"SQL_BIG_RESULT DATE_FORMAT( {$fromUnixTime}, '{$timescale}' ) AS time_as_alias, " . implode( ', ', array_unique( $this->series ) ) . ( $this->groupBy ? ", " . $this->groupBy : '' ),
|
||||
$this->table,
|
||||
$where,
|
||||
'time_as_alias ASC',
|
||||
|
||||
@@ -126,6 +126,11 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
* @brief Error(s) to show on chart UI
|
||||
*/
|
||||
public $errors = array();
|
||||
|
||||
/**
|
||||
* @brief Saved custom filters
|
||||
*/
|
||||
public $savedCustomFilters = array();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
@@ -267,8 +272,8 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
$url = $url->setQueryString( 'end', array( $this->identifier => $this->end->getTimestamp() ) );
|
||||
}
|
||||
catch ( \Exception $e ) {}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if ( isset( \IPS\Request::i()->filters[ $this->identifier ] ) )
|
||||
{
|
||||
$url = $url->setQueryString( 'filters', '' );
|
||||
@@ -299,10 +304,32 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
{
|
||||
if( $chart['chart_id'] == \IPS\Request::i()->chartId )
|
||||
{
|
||||
\IPS\Request::i()->filters = array( $this->identifier => json_decode( $chart['chart_configuration'], true ) );
|
||||
$filters = array();
|
||||
foreach( json_decode( $chart['chart_configuration'], true ) as $key => $value )
|
||||
{
|
||||
if ( \mb_substr( $key, 0, 11 ) == 'customform_' )
|
||||
{
|
||||
$this->savedCustomFilters[ \mb_substr( $key, 11 ) ] = $value;
|
||||
}
|
||||
else
|
||||
{
|
||||
$filters[ $key ] = $value;
|
||||
}
|
||||
}
|
||||
\IPS\Request::i()->filters = array( $this->identifier => $filters );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach( \IPS\Request::i() as $key => $value )
|
||||
{
|
||||
if ( $value and \mb_substr( $key, 0, 11 ) === 'customform_' )
|
||||
{
|
||||
$name = \mb_substr( preg_replace( '#' . $this->identifier . '#', '', $key ), 11 );
|
||||
|
||||
$this->savedCustomFilters[ $name ] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -311,7 +338,7 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
* @param array $data The data
|
||||
* @return void
|
||||
*/
|
||||
abstract public function compileForOutput(): void;
|
||||
abstract public function compileForOutput();
|
||||
|
||||
/**
|
||||
* Get the chart output
|
||||
@@ -335,8 +362,30 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
try
|
||||
{
|
||||
/* If we have filters, we can save them */
|
||||
if( \count( $this->availableFilters ) > 0 )
|
||||
if( \count( $this->availableFilters ) > 0 or $this->customFiltersForm )
|
||||
{
|
||||
/* Generate a form so we can save our filters as a new saved chart */
|
||||
$this->form = new \IPS\Helpers\Form;
|
||||
$this->form->class = 'ipsForm_vertical';
|
||||
|
||||
if ( $this->customFiltersForm )
|
||||
{
|
||||
if ( $customValues = $this->getCustomFiltersForm()->values( TRUE ) )
|
||||
{
|
||||
foreach( $customValues as $key => $value )
|
||||
{
|
||||
$this->form->hiddenValues['customform_' . $key ] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If we have a sub selector from a node form, add on the identifier and pass off to the form to show the ajax */
|
||||
if ( \IPS\Request::i()->_nodeSelectName )
|
||||
{
|
||||
\IPS\Request::i()->_nodeSelectName = $this->identifier . \IPS\Request::i()->_nodeSelectName;
|
||||
return (string) $this->getCustomFiltersForm();
|
||||
}
|
||||
|
||||
/* We have an existing chart ID */
|
||||
if( isset( \IPS\Request::i()->chartId ) AND \IPS\Request::i()->chartId != '_default' )
|
||||
{
|
||||
@@ -350,10 +399,18 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate a form so we can save our filters as a new saved chart */
|
||||
$this->form = new \IPS\Helpers\Form;
|
||||
$this->form->class = 'ipsForm_vertical';
|
||||
|
||||
$custom = array();
|
||||
$chartFilters = ( isset( \IPS\Request::i()->chartFilters ) and \IPS\Request::i()->chartFilters ) ? \IPS\Request::i()->chartFilters : array();
|
||||
|
||||
foreach( \IPS\Request::i() as $key => $value )
|
||||
{
|
||||
if ( \mb_substr( $key, 0, 11 ) === 'customform_' )
|
||||
{
|
||||
$custom[ preg_replace( '#' . $this->identifier . '#', '', $key ) ] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$this->form->add( new \IPS\Helpers\Form\Text( 'custom_chart_title', $title, TRUE ) );
|
||||
|
||||
if( $values = $this->form->values() )
|
||||
@@ -369,24 +426,32 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
/* And we want to save our filter updates */
|
||||
if( isset( \IPS\Request::i()->saveFilters ) )
|
||||
{
|
||||
\IPS\Db::i()->update( 'core_saved_charts', array( 'chart_configuration' => json_encode( \IPS\Request::i()->chartFilters ) ), array( 'chart_id=? AND chart_member=?', \IPS\Request::i()->chartId, \IPS\Member::loggedIn()->member_id ) );
|
||||
\IPS\Db::i()->update( 'core_saved_charts', array( 'chart_configuration' => json_encode( array_merge( $chartFilters, $custom ) ) ), array( 'chart_id=? AND chart_member=?', \IPS\Request::i()->chartId, \IPS\Member::loggedIn()->member_id ) );
|
||||
}
|
||||
}
|
||||
/* We are not viewing a saved chart */
|
||||
else
|
||||
{
|
||||
/* Generate a form so we can save our filters as a new saved chart */
|
||||
$this->form = new \IPS\Helpers\Form;
|
||||
$this->form->class = 'ipsForm_vertical';
|
||||
$this->form->add( new \IPS\Helpers\Form\Text( 'custom_chart_title', NULL, TRUE ) );
|
||||
|
||||
|
||||
if( $values = $this->form->values() )
|
||||
{
|
||||
$custom = array();
|
||||
foreach( \IPS\Request::i() as $key => $value )
|
||||
{
|
||||
if ( \mb_substr( $key, 0, 11 ) === 'customform_' )
|
||||
{
|
||||
$custom[ preg_replace( '#' . $this->identifier . '#', '', $key ) ] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$chartFilters = ( isset( \IPS\Request::i()->chartFilters ) and \IPS\Request::i()->chartFilters ) ? \IPS\Request::i()->chartFilters : array();
|
||||
|
||||
/* Store the new chart */
|
||||
$id = \IPS\Db::i()->insert( 'core_saved_charts', array(
|
||||
'chart_member' => \IPS\Member::loggedIn()->member_id,
|
||||
'chart_controller' => \IPS\Request::i()->app . '_' . \IPS\Request::i()->module . '_' . \IPS\Request::i()->controller . ( \IPS\Request::i()->tab ? '_' . \IPS\Request::i()->tab : '' ),
|
||||
'chart_configuration' => json_encode( \IPS\Request::i()->chartFilters ),
|
||||
'chart_configuration' => json_encode( array_merge( $chartFilters, $custom ) ),
|
||||
'chart_title' => $values['custom_chart_title'],
|
||||
) );
|
||||
|
||||
@@ -419,7 +484,7 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
|
||||
/* Get data */
|
||||
$output = '';
|
||||
if ( !empty( $this->series ) )
|
||||
if ( !empty( $this->series ) or $this->customFiltersForm )
|
||||
{
|
||||
$output = $this->getOutput();
|
||||
}
|
||||
@@ -437,7 +502,7 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
{
|
||||
$chartOutput = \IPS\Theme::i()->getTemplate( 'global', 'core', 'global' )->dynamicChart( $this, $output );
|
||||
|
||||
if( \count( $this->availableFilters ) > 0 AND ( !\IPS\Request::i()->isAjax() OR ( \IPS\Request::i()->tab AND !\IPS\Request::i()->chartId ) ) )
|
||||
if( ( \count( $this->availableFilters ) > 0 or $this->customFiltersForm ) AND ( !\IPS\Request::i()->isAjax() OR ( \IPS\Request::i()->tab AND !\IPS\Request::i()->chartId ) ) )
|
||||
{
|
||||
return \IPS\Theme::i()->getTemplate( 'global', 'core' )->tabs( $this->getChartTabs(), ( isset( \IPS\Request::i()->chartId ) ) ? \IPS\Request::i()->chartId : NULL, $chartOutput, $this->url, 'chartId', 'ipsTabs_small ipsTabs_contained' );
|
||||
}
|
||||
@@ -469,7 +534,7 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
*/
|
||||
protected function getChartTabs()
|
||||
{
|
||||
$tabs = array( '' => 'dynamic_chart_overview' );
|
||||
$tabs = array( '_default' => 'dynamic_chart_overview' );
|
||||
|
||||
foreach( $this->loadAvailableChartTabs() as $chart )
|
||||
{
|
||||
@@ -564,6 +629,35 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom filter form
|
||||
*
|
||||
* @return \IPS\Helpers\Form
|
||||
*/
|
||||
public function getCustomFiltersForm()
|
||||
{
|
||||
$customForm = new \IPS\Helpers\Form('filter_form', 'chart_customfilters_save');
|
||||
$customForm->class = 'ipsForm_vertical';
|
||||
|
||||
if ( isset( \IPS\Request::i()->chartId ) and \IPS\Request::i()->chartId != '_default' )
|
||||
{
|
||||
$customForm->hiddenValues['chartId'] = \IPS\Request::i()->chartId;
|
||||
}
|
||||
|
||||
foreach( $this->customFiltersForm['form'] as $field )
|
||||
{
|
||||
if ( ! preg_match( '#^' . $this->identifier . '#', $field->name ) )
|
||||
{
|
||||
$langKey = $field->name;
|
||||
$field->name = $this->identifier . $field->name;
|
||||
\IPS\Member::loggedIn()->language()->words[ $field->name ] = \IPS\Member::loggedIn()->language()->get( $langKey );
|
||||
}
|
||||
$customForm->add( $field );
|
||||
}
|
||||
|
||||
return $customForm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Download as CSV
|
||||
*
|
||||
@@ -572,7 +666,7 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
* @param string|NULL $fileName File Name, or NULL to use the title defined by this object.
|
||||
* @return void
|
||||
*/
|
||||
public function download( ?array $rawHeaders = NULL, ?array $rawRows = NULL, ?string $fileName = NULL ): void
|
||||
public function download( ?array $rawHeaders = NULL, ?array $rawRows = NULL, ?string $fileName = NULL )
|
||||
{
|
||||
/* Compile the data */
|
||||
$file = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' );
|
||||
|
||||
Reference in new issue
Block a user