Version 4.5.0
This commit is contained in:
1 parent
1a0c7fd3c2
commit
f79dcf067a
3791 files changed
+248032
-76372
No files matched your search
@@ -11,7 +11,7 @@
|
||||
namespace IPS\Helpers\Chart;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
@@ -46,7 +46,7 @@ class _Callback extends \IPS\Helpers\Chart\Dynamic
|
||||
*/
|
||||
public function __construct( \IPS\Http\Url $url, $callback=NULL, $title='', $options=array(), $defaultType='AreaChart', $defaultTimescale='monthly', $defaultTimes=array( 'start' => 0, 'end' => 0 ), $identifier='', $minimumDate=NULL )
|
||||
{
|
||||
$this->identifier = \substr( md5( (string) $url ), 0, 6 ) . $identifier;
|
||||
$this->identifier = \substr( md5( (string) $url ), 0, 6 ) . $identifier . ( \IPS\Request::i()->chartId ?: '_default' );
|
||||
$this->callback = $callback;
|
||||
|
||||
parent::__construct( $url, $title, $options, $defaultType, $defaultTimescale, $defaultTimes, $identifier, $minimumDate );
|
||||
@@ -71,7 +71,7 @@ class _Callback extends \IPS\Helpers\Chart\Dynamic
|
||||
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $name );
|
||||
$filterKey = $name;
|
||||
|
||||
if ( !$filterable or !isset( \IPS\Request::i()->filters[ $this->identifier ] ) or in_array( $filterKey, \IPS\Request::i()->filters[ $this->identifier ] ) )
|
||||
if ( !$filterable or !isset( \IPS\Request::i()->filters[ $this->identifier ] ) or \in_array( $filterKey, \IPS\Request::i()->filters[ $this->identifier ] ) )
|
||||
{
|
||||
if ( $this->type !== 'PieChart' and $this->type !== 'GeoChart' )
|
||||
{
|
||||
@@ -96,40 +96,39 @@ class _Callback extends \IPS\Helpers\Chart\Dynamic
|
||||
$this->availableFilters[ $filterKey ] = $name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the chart output
|
||||
* Compile Data for Output
|
||||
*
|
||||
* @return string
|
||||
* @param array $data The data
|
||||
* @return void
|
||||
*/
|
||||
public function getOutput()
|
||||
public function compileForOutput(): void
|
||||
{
|
||||
/* Init data */
|
||||
$data = $this->initData();
|
||||
|
||||
/* Get rows */
|
||||
$callbackFunction = $this->callback;
|
||||
$rows = $callbackFunction( $this );
|
||||
|
||||
/* Pie Chart */
|
||||
if ( $this->type === 'PieChart' or $this->type === 'GeoChart' )
|
||||
{
|
||||
$rows = call_user_func( $this->callback, $this );
|
||||
|
||||
{
|
||||
foreach ( $rows as $k => $v )
|
||||
{
|
||||
if( count( $this->availableFilters ) and !in_array( $k, $this->currentFilters ) )
|
||||
if( \count( $this->availableFilters ) and !\in_array( $k, $this->currentFilters ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->addRow( array( 'key' => $this->availableFilters[ $k ], 'value' => $v ) );
|
||||
}
|
||||
|
||||
$output = $this->render( $this->type, $this->options, $this->format );
|
||||
}
|
||||
|
||||
/* Graph */
|
||||
else
|
||||
{
|
||||
$rows = call_user_func( $this->callback, $this );
|
||||
|
||||
foreach ( $rows as $row )
|
||||
{
|
||||
$result = array();
|
||||
@@ -205,14 +204,14 @@ class _Callback extends \IPS\Helpers\Chart\Dynamic
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->addRow( array_merge( array( $datetime ), array_fill( 0, count( $this->series ), 0 ) ) );
|
||||
$this->addRow( array_merge( array( $datetime ), array_fill( 0, \count( $this->series ), 0 ) ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( count($d) < count($this->series) )
|
||||
if( \count($d) < \count($this->series) )
|
||||
{
|
||||
$this->addRow( array_merge( array( $datetime ), $d, array_fill( 0, count($this->series) - count($d), 0 ) ) );
|
||||
$this->addRow( array_merge( array( $datetime ), $d, array_fill( 0, \count($this->series) - \count($d), 0 ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -221,14 +220,28 @@ class _Callback extends \IPS\Helpers\Chart\Dynamic
|
||||
}
|
||||
}
|
||||
|
||||
if ( count( $data ) === 1 )
|
||||
if ( \count( $data ) === 1 )
|
||||
{
|
||||
$this->options['domainAxis']['type'] = 'category';
|
||||
}
|
||||
|
||||
$output = $this->render( $this->type, $this->options, $this->format );
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
/**
|
||||
* Get the chart output
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOutput()
|
||||
{
|
||||
$this->compileForOutput();
|
||||
if ( isset( \IPS\Request::i()->download ) )
|
||||
{
|
||||
return $this->download();
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->render( $this->type, $this->options, $this->format );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
namespace IPS\Helpers;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
@@ -84,7 +84,7 @@ class _Chart
|
||||
*/
|
||||
public function addRow( $values )
|
||||
{
|
||||
if ( count( $values ) !== count( $this->headers ) )
|
||||
if ( \count( $values ) !== \count( $this->headers ) )
|
||||
{
|
||||
throw new \LengthException('COLUMN_COUNT_MISMATCH');
|
||||
}
|
||||
@@ -96,21 +96,21 @@ class _Chart
|
||||
switch ( $data['type'] )
|
||||
{
|
||||
case 'string':
|
||||
if ( !is_string( $values[ $i ] ) )
|
||||
if ( !\is_string( $values[ $i ] ) )
|
||||
{
|
||||
throw new \InvalidArgumentException( "VALUE_{$i}_NOT_STRING" );
|
||||
}
|
||||
break;
|
||||
|
||||
case 'number':
|
||||
if ( !is_numeric( $values[ $i ] ) and !is_null( $values[ $i ] ) )
|
||||
if ( !\is_numeric( $values[ $i ] ) and !\is_null( $values[ $i ] ) )
|
||||
{
|
||||
throw new \InvalidArgumentException( "VALUE_{$i}_NOT_NUMBER" );
|
||||
}
|
||||
break;
|
||||
|
||||
case 'bool':
|
||||
if ( !is_bool( $values[ $i ] ) )
|
||||
if ( !\is_bool( $values[ $i ] ) )
|
||||
{
|
||||
throw new \InvalidArgumentException( "VALUE_{$i}_NOT_BOOL" );
|
||||
}
|
||||
@@ -146,11 +146,11 @@ class _Chart
|
||||
{
|
||||
if ( !\IPS\Request::i()->isAjax() )
|
||||
{
|
||||
\IPS\Output::i()->jsFiles[] = 'https://www.google.com/jsapi';
|
||||
\IPS\Output::i()->headJs .= "google.load('visualization', '1.0', {'packages':['corechart']}); ";
|
||||
\IPS\Output::i()->jsFiles[] = 'https://www.gstatic.com/charts/loader.js';
|
||||
\IPS\Output::i()->headJs .= "google.charts.load( '47', { 'packages':['corechart'] } );";
|
||||
}
|
||||
|
||||
if ( !$this->numbersCanBeNegative and in_array( $type, array( 'LineChart', 'ColumnChart' ) ) and !isset( $options['vAxis']['viewWindow']['min'] ) )
|
||||
if ( !$this->numbersCanBeNegative and \in_array( $type, array( 'LineChart', 'ColumnChart' ) ) and !isset( $options['vAxis']['viewWindow']['min'] ) )
|
||||
{
|
||||
$options['vAxis']['viewWindow']['min'] = 0;
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
namespace IPS\Helpers\Chart;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
@@ -83,7 +83,7 @@ class _Database extends \IPS\Helpers\Chart\Dynamic
|
||||
{
|
||||
$this->table = $table;
|
||||
$this->dateField = $dateField;
|
||||
$this->identifier = \substr( md5( $table . $dateField ), 0, 6 ) . ( $identifier ?: ( \IPS\Request::i()->chartId ?: '_default' ) );
|
||||
$this->identifier = \substr( md5( $table . $dateField ), 0, 6 ) . $identifier . ( \IPS\Request::i()->chartId ?: '_default' );
|
||||
|
||||
if ( !empty( $tableInclude ) )
|
||||
{
|
||||
@@ -121,7 +121,7 @@ class _Database extends \IPS\Helpers\Chart\Dynamic
|
||||
$filterKey = $name;
|
||||
}
|
||||
|
||||
if ( !$filterable or !isset( \IPS\Request::i()->filters[ $this->identifier ] ) or in_array( $filterKey, \IPS\Request::i()->filters[ $this->identifier ] ) )
|
||||
if ( !$filterable or !isset( \IPS\Request::i()->filters[ $this->identifier ] ) or \in_array( $filterKey, \IPS\Request::i()->filters[ $this->identifier ] ) )
|
||||
{
|
||||
if ( $this->type !== 'PieChart' and $this->type !== 'GeoChart' )
|
||||
{
|
||||
@@ -153,21 +153,13 @@ class _Database extends \IPS\Helpers\Chart\Dynamic
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the chart output
|
||||
* Compile Data for Output
|
||||
*
|
||||
* @return string
|
||||
* @param array $data The data
|
||||
* @return void
|
||||
*/
|
||||
public function getOutput()
|
||||
public function compileForOutput(): void
|
||||
{
|
||||
/* Auto-support tables where appropriate */
|
||||
if ( !empty( $this->tableInclude ) )
|
||||
{
|
||||
if( !array_search( 'Table', $this->availableTypes ) )
|
||||
{
|
||||
$this->availableTypes[] = 'Table';
|
||||
}
|
||||
}
|
||||
|
||||
/* Init data */
|
||||
$data = $this->initData();
|
||||
|
||||
@@ -195,7 +187,7 @@ class _Database extends \IPS\Helpers\Chart\Dynamic
|
||||
break;
|
||||
|
||||
case 'weekly':
|
||||
$timescale = '%Y-%u';
|
||||
$timescale = '%x-%v';
|
||||
break;
|
||||
|
||||
case 'monthly':
|
||||
@@ -203,40 +195,6 @@ class _Database extends \IPS\Helpers\Chart\Dynamic
|
||||
break;
|
||||
}
|
||||
|
||||
/* Table... */
|
||||
if ( $this->type === 'Table' )
|
||||
{
|
||||
/* Are we filtering? */
|
||||
if( $this->groupBy )
|
||||
{
|
||||
if( count( $this->availableFilters ) AND count( $this->currentFilters ) )
|
||||
{
|
||||
$where[] = array( \IPS\Db::i()->in( $this->groupBy, $this->currentFilters ) );
|
||||
}
|
||||
}
|
||||
|
||||
$table = new \IPS\Helpers\Table\Db( $this->table, $this->url, $where );
|
||||
|
||||
/* Reformat chart join for the table helper */
|
||||
if( \is_array( $this->joins ) )
|
||||
{
|
||||
array_walk( $this->joins, function ( $item ) use ( $table )
|
||||
{
|
||||
$table->joins[] = array('from' => $item[0], 'where' => $item[1], 'type' => isset( $item[2] ) ? $item[2] : 'LEFT');
|
||||
} );
|
||||
}
|
||||
|
||||
if( count( $this->tableInclude ) )
|
||||
{
|
||||
$table->include = $this->tableInclude;
|
||||
}
|
||||
$table->parsers = $this->tableParsers;
|
||||
$table->sortBy = $table->sortBy ?: $this->dateField;
|
||||
$output = (string) $table;
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/* Pie Chart */
|
||||
if ( $this->type === 'PieChart' or $this->type === 'GeoChart' )
|
||||
{
|
||||
@@ -252,7 +210,7 @@ class _Database extends \IPS\Helpers\Chart\Dynamic
|
||||
$this->groupBy
|
||||
)->setKeyField( $this->groupBy )->setValueField( $key );
|
||||
|
||||
if( count( $this->joins ) )
|
||||
if( \count( $this->joins ) )
|
||||
{
|
||||
foreach( $this->joins as $join )
|
||||
{
|
||||
@@ -262,14 +220,12 @@ class _Database extends \IPS\Helpers\Chart\Dynamic
|
||||
|
||||
foreach ( $stmt as $k => $v )
|
||||
{
|
||||
if( count( $this->availableFilters ) and !in_array( $k, $this->currentFilters ) )
|
||||
if( \count( $this->availableFilters ) and !\in_array( $k, $this->currentFilters ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$this->addRow( array( 'key' => $this->availableFilters[ $k ], 'value' => $v ) );
|
||||
}
|
||||
|
||||
$output = $this->render( $this->type, $this->options, $this->format );
|
||||
}
|
||||
|
||||
/* Graph */
|
||||
@@ -277,7 +233,7 @@ class _Database extends \IPS\Helpers\Chart\Dynamic
|
||||
{
|
||||
/* Fetch */
|
||||
$fromUnixTime = "FROM_UNIXTIME( IFNULL( {$this->dateField}, 0 ) )";
|
||||
if ( !$this->timezoneError and \IPS\Member::loggedIn()->timezone and in_array( \IPS\Member::loggedIn()->timezone, \DateTimeZone::listIdentifiers() ) )
|
||||
if ( !$this->timezoneError and \IPS\Member::loggedIn()->timezone and \in_array( \IPS\Member::loggedIn()->timezone, \DateTimeZone::listIdentifiers() ) )
|
||||
{
|
||||
$fromUnixTime = "CONVERT_TZ( {$fromUnixTime}, @@session.time_zone, '" . \IPS\Db::i()->escape_string( \IPS\Member::loggedIn()->timezone ) . "' )";
|
||||
}
|
||||
@@ -290,7 +246,7 @@ class _Database extends \IPS\Helpers\Chart\Dynamic
|
||||
$this->groupBy ? array( 'time_as_alias', $this->groupBy ) : 'time_as_alias'
|
||||
);
|
||||
|
||||
if( count( $this->joins ) )
|
||||
if( \count( $this->joins ) )
|
||||
{
|
||||
foreach( $this->joins as $join )
|
||||
{
|
||||
@@ -304,7 +260,7 @@ class _Database extends \IPS\Helpers\Chart\Dynamic
|
||||
|
||||
if( $this->groupBy )
|
||||
{
|
||||
if( count( $this->availableFilters ) AND !in_array( $row[ $this->groupBy ], $this->currentFilters ) )
|
||||
if( \count( $this->availableFilters ) AND !\in_array( $row[ $this->groupBy ], $this->currentFilters ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -396,7 +352,7 @@ class _Database extends \IPS\Helpers\Chart\Dynamic
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->addRow( array_merge( array( $datetime ), array_fill( 0, count( $this->series ), 0 ) ) );
|
||||
$this->addRow( array_merge( array( $datetime ), array_fill( 0, \count( $this->series ), 0 ) ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -413,9 +369,9 @@ class _Database extends \IPS\Helpers\Chart\Dynamic
|
||||
}
|
||||
else
|
||||
{
|
||||
if( count($d) < count($this->series) )
|
||||
if( \count($d) < \count($this->series) )
|
||||
{
|
||||
$this->addRow( array_merge( array( $datetime ), $d, array_fill( 0, count($this->series) - count($d), 0 ) ) );
|
||||
$this->addRow( array_merge( array( $datetime ), $d, array_fill( 0, \count($this->series) - \count($d), 0 ) ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -425,14 +381,113 @@ class _Database extends \IPS\Helpers\Chart\Dynamic
|
||||
}
|
||||
}
|
||||
|
||||
if ( count( $data ) === 1 )
|
||||
if ( \count( $data ) === 1 )
|
||||
{
|
||||
$this->options['domainAxis']['type'] = 'category';
|
||||
}
|
||||
|
||||
$output = $this->render( $this->type, $this->options, $this->format );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the chart output
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getOutput()
|
||||
{
|
||||
/* Auto-support tables where appropriate */
|
||||
if ( !empty( $this->tableInclude ) )
|
||||
{
|
||||
if( !array_search( 'Table', $this->availableTypes ) )
|
||||
{
|
||||
$this->availableTypes[] = 'Table';
|
||||
}
|
||||
}
|
||||
|
||||
/* Work out where clause */
|
||||
$where = $this->where;
|
||||
$where[] = array( "{$this->dateField}>?", 0 );
|
||||
if ( $this->start )
|
||||
{
|
||||
$where[] = array( "{$this->dateField}>?", $this->start->getTimestamp() );
|
||||
}
|
||||
if ( $this->end )
|
||||
{
|
||||
$where[] = array( "{$this->dateField}<?", $this->end->getTimestamp() );
|
||||
}
|
||||
|
||||
/* Table... */
|
||||
if ( $this->type === 'Table' )
|
||||
{
|
||||
/* Are we filtering? */
|
||||
if( $this->groupBy )
|
||||
{
|
||||
if( \count( $this->availableFilters ) AND \count( $this->currentFilters ) )
|
||||
{
|
||||
$where[] = array( \IPS\Db::i()->in( $this->groupBy, $this->currentFilters ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
$table = new \IPS\Helpers\Table\Db( $this->table, $this->url, $where );
|
||||
|
||||
/* Reformat chart join for the table helper */
|
||||
if( \is_array( $this->joins ) )
|
||||
{
|
||||
array_walk( $this->joins, function ( $item ) use ( $table )
|
||||
{
|
||||
$table->joins[] = array('from' => $item[0], 'where' => $item[1], 'type' => isset( $item[2] ) ? $item[2] : 'LEFT');
|
||||
} );
|
||||
}
|
||||
|
||||
if( \count( $this->tableInclude ) )
|
||||
{
|
||||
$table->include = $this->tableInclude;
|
||||
}
|
||||
$table->parsers = $this->tableParsers;
|
||||
$table->sortBy = $table->sortBy ?: $this->dateField;
|
||||
|
||||
if ( isset( \IPS\Request::i()->download ) )
|
||||
{
|
||||
$headers = array();
|
||||
foreach( $table->getHeaders( $table->getAdvancedSearchValues() ) AS $header )
|
||||
{
|
||||
if ( $header === '_buttons' )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$headers[] = array(
|
||||
'label' => \IPS\Member::loggedIn()->language()->addToStack( $header ),
|
||||
'type' => 'string'
|
||||
);
|
||||
}
|
||||
|
||||
$rows = array();
|
||||
foreach( $table->getRows( $table->getAdvancedSearchValues() ) AS $k => $v )
|
||||
{
|
||||
$rows[$k] = array();
|
||||
foreach( $v AS $j => $value )
|
||||
{
|
||||
$rows[$k][] = trim( strip_tags( (string) $value ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $this->download( $headers, $rows, \IPS\Output::i()->title );
|
||||
}
|
||||
|
||||
$output = (string) $table;
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
$this->compileForOutput();
|
||||
if ( isset( \IPS\Request::i()->download ) )
|
||||
{
|
||||
return $this->download();
|
||||
}
|
||||
else
|
||||
{
|
||||
return $this->render( $this->type, $this->options, $this->format );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@
|
||||
namespace IPS\Helpers\Chart;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
if ( !\defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
@@ -66,6 +66,11 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
* @brief Type
|
||||
*/
|
||||
public $type;
|
||||
|
||||
/**
|
||||
* @brief Search term
|
||||
*/
|
||||
public $searchTerm = null;
|
||||
|
||||
/**
|
||||
* @brief Available Types
|
||||
@@ -102,6 +107,11 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
*/
|
||||
public $timezoneError = FALSE;
|
||||
|
||||
/**
|
||||
* @brief If we need to show a timezone warning, we usually include a link to learn more - set this to TRUE to hide the link
|
||||
*/
|
||||
public $hideTimezoneLink = FALSE;
|
||||
|
||||
/**
|
||||
* @brief If set to an \IPS\DateTime instance, minimum time will be checked against this value
|
||||
*/
|
||||
@@ -157,11 +167,11 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
$this->title = $title;
|
||||
$this->options = $options;
|
||||
$this->timescale = $defaultTimescale;
|
||||
$this->start = $defaultTimes['start'];
|
||||
$this->end = $defaultTimes['end'];
|
||||
$this->start = $defaultTimes['start'] ?: \IPS\DateTime::create()->sub( new \DateInterval('P6M') );
|
||||
$this->end = $defaultTimes['end'] ?: \IPS\DateTime::create();
|
||||
$this->minimumDate = $minimumDate;
|
||||
|
||||
if ( isset( \IPS\Request::i()->type[ $this->identifier ] ) and in_array( \IPS\Request::i()->type[ $this->identifier ], $this->availableTypes ) )
|
||||
if ( isset( \IPS\Request::i()->type[ $this->identifier ] ) and \in_array( \IPS\Request::i()->type[ $this->identifier ], $this->availableTypes ) )
|
||||
{
|
||||
$this->type = \IPS\Request::i()->type[ $this->identifier ];
|
||||
$url = $url->setQueryString( 'type', array( $this->identifier => $this->type ) );
|
||||
@@ -171,7 +181,14 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
$this->type = $defaultType;
|
||||
}
|
||||
|
||||
if ( isset( \IPS\Request::i()->timescale[ $this->identifier ] ) and in_array( \IPS\Request::i()->timescale[ $this->identifier ], array( 'hourly', 'daily', 'weekly', 'monthly' ) ) )
|
||||
/* Are we searching? The chart controller should inspect this property if it supports searching to limit the series it adds. */
|
||||
if( isset( $this->options['limitSearch'] ) AND isset( \IPS\Request::i()->search[ $this->identifier ] ) )
|
||||
{
|
||||
$this->searchTerm = \IPS\Request::i()->search[ $this->identifier ];
|
||||
}
|
||||
|
||||
/* Change timescale */
|
||||
if ( isset( \IPS\Request::i()->timescale[ $this->identifier ] ) and \in_array( \IPS\Request::i()->timescale[ $this->identifier ], array( 'hourly', 'daily', 'weekly', 'monthly' ) ) )
|
||||
{
|
||||
if( \IPS\Request::i()->timescale[ $this->identifier ] != 'hourly' OR ( \IPS\Request::i()->timescale[ $this->identifier ] == 'hourly' AND $this->enableHourly === TRUE ) )
|
||||
{
|
||||
@@ -190,13 +207,17 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
$this->addHeader( \IPS\Member::loggedIn()->language()->addToStack('date'), ( $this->timescale == 'none' OR $this->timescale == 'hourly' ) ? 'datetime' : 'date' );
|
||||
}
|
||||
|
||||
if ( isset( \IPS\Request::i()->start[ $this->identifier ] ) and \IPS\Request::i()->start[ $this->identifier ] )
|
||||
if ( isset( \IPS\Request::i()->start[ $this->identifier ] ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
$originalStart = $this->start;
|
||||
|
||||
if ( is_numeric( \IPS\Request::i()->start[ $this->identifier ] ) )
|
||||
if( !\IPS\Request::i()->start[ $this->identifier ] )
|
||||
{
|
||||
$this->start = 0;
|
||||
}
|
||||
elseif ( \is_numeric( \IPS\Request::i()->start[ $this->identifier ] ) )
|
||||
{
|
||||
$this->start = \IPS\DateTime::ts( \IPS\Request::i()->start[ $this->identifier ] );
|
||||
}
|
||||
@@ -223,11 +244,15 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
catch ( \Exception $e ) {}
|
||||
}
|
||||
|
||||
if ( isset( \IPS\Request::i()->end[ $this->identifier ] ) and \IPS\Request::i()->end[ $this->identifier ] )
|
||||
if ( isset( \IPS\Request::i()->end[ $this->identifier ] ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( is_numeric( \IPS\Request::i()->end[ $this->identifier ] ) )
|
||||
if( !\IPS\Request::i()->end[ $this->identifier ] )
|
||||
{
|
||||
$this->end = \IPS\DateTime::create();
|
||||
}
|
||||
elseif ( \is_numeric( \IPS\Request::i()->end[ $this->identifier ] ) )
|
||||
{
|
||||
$this->end = \IPS\DateTime::ts( \IPS\Request::i()->end[ $this->identifier ] );
|
||||
}
|
||||
@@ -251,7 +276,7 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
|
||||
$this->url = $url;
|
||||
|
||||
if ( \IPS\Member::loggedIn()->timezone and in_array( \IPS\Member::loggedIn()->timezone, \DateTimeZone::listIdentifiers() ) )
|
||||
if ( \IPS\Member::loggedIn()->timezone and \in_array( \IPS\Member::loggedIn()->timezone, \DateTimeZone::listIdentifiers() ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -280,6 +305,14 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile Data for Output
|
||||
*
|
||||
* @param array $data The data
|
||||
* @return void
|
||||
*/
|
||||
abstract public function compileForOutput(): void;
|
||||
|
||||
/**
|
||||
* Get the chart output
|
||||
*
|
||||
@@ -302,7 +335,7 @@ 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 )
|
||||
{
|
||||
/* We have an existing chart ID */
|
||||
if( isset( \IPS\Request::i()->chartId ) AND \IPS\Request::i()->chartId != '_default' )
|
||||
@@ -404,7 +437,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 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' );
|
||||
}
|
||||
@@ -471,7 +504,7 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
{
|
||||
$filters = $this->currentFilters;
|
||||
|
||||
if ( in_array( $filter, $filters ) )
|
||||
if ( \in_array( $filter, $filters ) )
|
||||
{
|
||||
unset( $filters[ array_search( $filter, $filters ) ] );
|
||||
}
|
||||
@@ -502,7 +535,7 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
case 'hourly':
|
||||
$data[ $date->format( 'Y-n-j-h-i-s' ) ] = array();
|
||||
|
||||
$date->add( new \DateInterval( 'P1H' ) );
|
||||
$date->add( new \DateInterval( 'PT1H' ) );
|
||||
break;
|
||||
|
||||
case 'daily':
|
||||
@@ -530,4 +563,88 @@ abstract class _Dynamic extends \IPS\Helpers\Chart
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Download as CSV
|
||||
*
|
||||
* @param array|NULL $headers Headers, or NULL to use headers defined by this object.
|
||||
* @param array|NULL $rows Rows, or NULL to use rows defined by this object.
|
||||
* @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
|
||||
{
|
||||
/* Compile the data */
|
||||
$file = tempnam( \IPS\TEMP_DIRECTORY, 'IPS' );
|
||||
$fh = fopen( $file, 'w' );
|
||||
|
||||
/* Set headers */
|
||||
$headers = array();
|
||||
|
||||
if ( $rawHeaders === NULL )
|
||||
{
|
||||
$rawHeaders = $this->headers;
|
||||
}
|
||||
|
||||
foreach( $rawHeaders AS $data )
|
||||
{
|
||||
$headers[] = $data['label'];
|
||||
}
|
||||
fputcsv( $fh, $headers );
|
||||
|
||||
/* Set Rows */
|
||||
|
||||
if ( $rawRows === NULL )
|
||||
{
|
||||
$rawRows = $this->rows;
|
||||
}
|
||||
|
||||
foreach( $rawRows AS $row )
|
||||
{
|
||||
$i = 0;
|
||||
$save = array();
|
||||
foreach( $rawHeaders AS $data )
|
||||
{
|
||||
switch( $data['type'] )
|
||||
{
|
||||
/* Booleans convert to string 'true' or 'false' */
|
||||
case 'bool':
|
||||
$save[] = ( $row[$i] ) ? 'true' : 'false';
|
||||
break;
|
||||
|
||||
/* Make dates human readable */
|
||||
case 'date':
|
||||
case 'datetime':
|
||||
case 'timeofday':
|
||||
$save[] = ( new \IPS\DateTime( $row[$i] ) )->fullYearLocaleDate();
|
||||
break;
|
||||
|
||||
/* Anything else can just save as-is */
|
||||
default:
|
||||
$save[] = $row[$i];
|
||||
break;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
fputcsv( $fh, $save );
|
||||
}
|
||||
|
||||
fclose( $fh );
|
||||
$csv = \file_get_contents( $file );
|
||||
if ( $fileName )
|
||||
{
|
||||
$name = $fileName;
|
||||
}
|
||||
else if ( $this->title )
|
||||
{
|
||||
$name = $this->title;
|
||||
}
|
||||
else
|
||||
{
|
||||
$name = \IPS\Output::i()->title;
|
||||
}
|
||||
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $name );
|
||||
\IPS\Member::loggedIn()->language()->parseOutputForDisplay( $csv );
|
||||
\IPS\Output::i()->sendOutput( $csv, 200, 'text/csv', array( 'Content-Disposition' => \IPS\Output::getContentDisposition( 'attachment', "{$name}.csv" ) ), FALSE, FALSE, FALSE );
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user