Page MenuHomePhabricator

D20452.id48803.diff
No OneTemporary

D20452.id48803.diff

diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php
--- a/src/__phutil_library_map__.php
+++ b/src/__phutil_library_map__.php
@@ -2097,6 +2097,7 @@
'PhabricatorAccessLog' => 'infrastructure/log/PhabricatorAccessLog.php',
'PhabricatorAccessLogConfigOptions' => 'applications/config/option/PhabricatorAccessLogConfigOptions.php',
'PhabricatorAccessibilitySetting' => 'applications/settings/setting/PhabricatorAccessibilitySetting.php',
+ 'PhabricatorAccumulateChartFunction' => 'applications/fact/chart/PhabricatorAccumulateChartFunction.php',
'PhabricatorActionListView' => 'view/layout/PhabricatorActionListView.php',
'PhabricatorActionView' => 'view/layout/PhabricatorActionView.php',
'PhabricatorActivitySettingsPanel' => 'applications/settings/panel/PhabricatorActivitySettingsPanel.php',
@@ -7961,6 +7962,7 @@
'PhabricatorAccessLog' => 'Phobject',
'PhabricatorAccessLogConfigOptions' => 'PhabricatorApplicationConfigOptions',
'PhabricatorAccessibilitySetting' => 'PhabricatorSelectSetting',
+ 'PhabricatorAccumulateChartFunction' => 'PhabricatorChartFunction',
'PhabricatorActionListView' => 'AphrontTagView',
'PhabricatorActionView' => 'AphrontView',
'PhabricatorActivitySettingsPanel' => 'PhabricatorSettingsPanel',
diff --git a/src/applications/fact/chart/PhabricatorAccumulateChartFunction.php b/src/applications/fact/chart/PhabricatorAccumulateChartFunction.php
new file mode 100644
--- /dev/null
+++ b/src/applications/fact/chart/PhabricatorAccumulateChartFunction.php
@@ -0,0 +1,37 @@
+<?php
+
+final class PhabricatorAccumulateChartFunction
+ extends PhabricatorChartFunction {
+
+ const FUNCTIONKEY = 'accumulate';
+
+ protected function newArguments() {
+ return array(
+ $this->newArgument()
+ ->setName('x')
+ ->setType('function')
+ ->setFunctionType('impulse')
+ ->setIsSourceFunction(true),
+ );
+ }
+
+ protected function newDatapoints(PhabricatorChartDataQuery $query) {
+ $source_function = $this->getSourceFunction();
+
+ // Use an unconstrained query to pull all the data from the underlying
+ // source. We need to accumulate data since the beginning of time to
+ // figure out the right Y-intercept -- otherwise, we'll always start at
+ // "0" wherever our domain begins.
+ $empty_query = new PhabricatorChartDataQuery();
+ $points = $source_function->getDatapoints($empty_query);
+
+ $accumulator = 0;
+ foreach ($points as $key => $point) {
+ $accumulator += $point['y'];
+ $points[$key]['y'] = $accumulator;
+ }
+
+ return $query->selectDatapoints($points);
+ }
+
+}
diff --git a/src/applications/fact/chart/PhabricatorChartDataQuery.php b/src/applications/fact/chart/PhabricatorChartDataQuery.php
--- a/src/applications/fact/chart/PhabricatorChartDataQuery.php
+++ b/src/applications/fact/chart/PhabricatorChartDataQuery.php
@@ -34,4 +34,43 @@
return $this->limit;
}
+ public function selectDatapoints(array $points) {
+ $x_min = $this->getMinimumValue();
+ $x_max = $this->getMaximumValue();
+ $limit = $this->getLimit();
+
+ if ($x_min !== null) {
+ foreach ($points as $key => $point) {
+ if ($point['x'] < $x_min) {
+ unset($points[$key]);
+ }
+ }
+ }
+
+ if ($x_max !== null) {
+ foreach ($points as $key => $point) {
+ if ($point['x'] > $x_max) {
+ unset($points[$key]);
+ }
+ }
+ }
+
+ // If we have too many data points, throw away some of the data.
+ if ($limit !== null) {
+ $count = count($points);
+ if ($count > $limit) {
+ $ii = 0;
+ $every = ceil($count / $limit);
+ foreach ($points as $key => $point) {
+ $ii++;
+ if (($ii % $every) && ($ii != $count)) {
+ unset($points[$key]);
+ }
+ }
+ }
+ }
+
+ return $points;
+ }
+
}
diff --git a/src/applications/fact/chart/PhabricatorChartFunction.php b/src/applications/fact/chart/PhabricatorChartFunction.php
--- a/src/applications/fact/chart/PhabricatorChartFunction.php
+++ b/src/applications/fact/chart/PhabricatorChartFunction.php
@@ -73,6 +73,27 @@
return $this->argumentParser;
}
+ public function selectAllFunctions() {
+ $result = array();
+ $result[] = $this;
+
+ $parser = $this->getArgumentParser();
+ foreach ($parser->getAllArguments() as $argument) {
+ if ($argument->getType() !== 'function') {
+ continue;
+ }
+
+ $name = $argument->getName();
+ $value = $this->getArgument($name);
+
+ foreach ($value->selectAllFunctions() as $subfunction) {
+ $result[] = $subfunction;
+ }
+ }
+
+ return $result;
+ }
+
public function loadData() {
return;
}
@@ -117,6 +138,34 @@
return false;
}
+ if ($this->isImpulseFunction()) {
+ return true;
+ }
+
+ $source_function = $this->getSourceFunction();
+ if ($source_function) {
+ return $source_function->hasDomain();
+ }
+
+ throw new PhutilMethodNotImplementedException();
+ }
+
+ public function isImpulseFunction() {
+ return false;
+ }
+
+ public function getDomain() {
+ // TODO: We can examine the data to fit a better domain.
+ if ($this->isImpulseFunction()) {
+ $now = PhabricatorTime::getNow();
+ return array($now - phutil_units('90 days in seconds'), $now);
+ }
+
+ $source_function = $this->getSourceFunction();
+ if ($source_function) {
+ return $source_function->getDomain();
+ }
+
throw new PhutilMethodNotImplementedException();
}
diff --git a/src/applications/fact/chart/PhabricatorChartFunctionArgument.php b/src/applications/fact/chart/PhabricatorChartFunctionArgument.php
--- a/src/applications/fact/chart/PhabricatorChartFunctionArgument.php
+++ b/src/applications/fact/chart/PhabricatorChartFunctionArgument.php
@@ -6,6 +6,7 @@
private $name;
private $type;
private $isSourceFunction;
+ private $functionType;
public function setName($name) {
$this->name = $name;
@@ -49,6 +50,15 @@
return $this->isSourceFunction;
}
+ public function setFunctionType($function_type) {
+ $this->functionType = $function_type;
+ return $this;
+ }
+
+ public function getFunctionType() {
+ return $this->functionType;
+ }
+
public function newValue($value) {
switch ($this->getType()) {
case 'fact-key':
@@ -119,8 +129,24 @@
implode(', ', array_keys($functions))));
}
- return id(clone $functions[$function_name])
+ $function = id(clone $functions[$function_name])
->setArguments($value);
+
+ switch ($this->getFunctionType()) {
+ case 'impulse':
+ if (!$function->isImpulseFunction()) {
+ throw new Exception(
+ pht(
+ 'Function must be an impulse function, but "%s" is not '.
+ 'an impulse function.',
+ $function_name));
+ }
+ break;
+ default:
+ break;
+ }
+
+ return $function;
case 'number':
if (!is_float($value) && !is_int($value)) {
throw new Exception(
diff --git a/src/applications/fact/chart/PhabricatorChartFunctionArgumentParser.php b/src/applications/fact/chart/PhabricatorChartFunctionArgumentParser.php
--- a/src/applications/fact/chart/PhabricatorChartFunctionArgumentParser.php
+++ b/src/applications/fact/chart/PhabricatorChartFunctionArgumentParser.php
@@ -72,6 +72,10 @@
return $this;
}
+ public function getAllArguments() {
+ return array_values($this->argumentMap);
+ }
+
public function parseArguments() {
$have_count = count($this->rawArguments);
$want_count = count($this->argumentMap);
diff --git a/src/applications/fact/chart/PhabricatorFactChartFunction.php b/src/applications/fact/chart/PhabricatorFactChartFunction.php
--- a/src/applications/fact/chart/PhabricatorFactChartFunction.php
+++ b/src/applications/fact/chart/PhabricatorFactChartFunction.php
@@ -22,6 +22,10 @@
return $fact->getFunctionArguments();
}
+ public function isImpulseFunction() {
+ return true;
+ }
+
public function loadData() {
$fact = $this->fact;
@@ -44,73 +48,32 @@
return;
}
- $points = array();
-
- $sum = 0;
- foreach ($data as $key => $row) {
- $sum += (int)$row['value'];
- $points[] = array(
- 'x' => (int)$row['epoch'],
- 'y' => $sum,
- );
- }
-
- $this->datapoints = $points;
- }
-
- public function getDatapoints(PhabricatorChartDataQuery $query) {
- $points = $this->datapoints;
- if (!$points) {
- return array();
- }
-
- $x_min = $query->getMinimumValue();
- $x_max = $query->getMaximumValue();
- $limit = $query->getLimit();
+ $map = array();
+ foreach ($data as $row) {
+ $value = (int)$row['value'];
+ $epoch = (int)$row['epoch'];
- if ($x_min !== null) {
- foreach ($points as $key => $point) {
- if ($point['x'] < $x_min) {
- unset($points[$key]);
- }
+ if (!isset($map[$epoch])) {
+ $map[$epoch] = 0;
}
- }
- if ($x_max !== null) {
- foreach ($points as $key => $point) {
- if ($point['x'] > $x_max) {
- unset($points[$key]);
- }
- }
+ $map[$epoch] += $value;
}
- // If we have too many data points, throw away some of the data.
- if ($limit !== null) {
- $count = count($points);
- if ($count > $limit) {
- $ii = 0;
- $every = ceil($count / $limit);
- foreach ($points as $key => $point) {
- $ii++;
- if (($ii % $every) && ($ii != $count)) {
- unset($points[$key]);
- }
- }
- }
+ $points = array();
+ foreach ($map as $x => $y) {
+ $points[] = array(
+ 'x' => $x,
+ 'y' => $y,
+ );
}
- return $points;
+ $this->datapoints = $points;
}
- public function hasDomain() {
- return true;
+ protected function newDatapoints(PhabricatorChartDataQuery $query) {
+ return $query->selectDatapoints($this->datapoints);
}
- public function getDomain() {
- // TODO: We can examine the data to fit a better domain.
-
- $now = PhabricatorTime::getNow();
- return array($now - phutil_units('90 days in seconds'), $now);
- }
}
diff --git a/src/applications/fact/chart/PhabricatorShiftChartFunction.php b/src/applications/fact/chart/PhabricatorShiftChartFunction.php
--- a/src/applications/fact/chart/PhabricatorShiftChartFunction.php
+++ b/src/applications/fact/chart/PhabricatorShiftChartFunction.php
@@ -22,7 +22,7 @@
}
protected function evaluateFunction($x) {
- return $x * $this->getArgument('shift');
+ return $x + $this->getArgument('shift');
}
}
diff --git a/src/applications/fact/controller/PhabricatorFactChartController.php b/src/applications/fact/controller/PhabricatorFactChartController.php
--- a/src/applications/fact/controller/PhabricatorFactChartController.php
+++ b/src/applications/fact/controller/PhabricatorFactChartController.php
@@ -14,12 +14,6 @@
$functions = array();
- $functions[] = id(new PhabricatorFactChartFunction())
- ->setArguments(array('tasks.count.create'));
-
- $functions[] = id(new PhabricatorFactChartFunction())
- ->setArguments(array('tasks.open-count.create'));
-
$x_function = id(new PhabricatorXChartFunction())
->setArguments(array());
@@ -42,12 +36,21 @@
array(
'scale',
array('x'),
- 0.001,
+ 0.0001,
),
),
- 10,
+ 200,
+ ),
+ 75,
+ ));
+
+ $functions[] = id(new PhabricatorAccumulateChartFunction())
+ ->setArguments(
+ array(
+ array(
+ 'fact',
+ 'tasks.count.create',
),
- 200,
));
list($domain_min, $domain_max) = $this->getDomain($functions);
@@ -61,6 +64,12 @@
->setMaximumValue($domain_max)
->setLimit(2000);
+ foreach ($functions as $function) {
+ foreach ($function->selectAllFunctions() as $subfunction) {
+ $subfunction->loadData();
+ }
+ }
+
$datasets = array();
foreach ($functions as $function) {
$function->setXAxis($axis);

File Metadata

Mime Type
text/plain
Expires
Mon, Mar 31, 7:04 PM (2 w, 2 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7708937
Default Alt Text
D20452.id48803.diff (12 KB)

Event Timeline