diff options
author | matt <matt@59fd770c-687e-43c8-a1e3-f5a4ff64c105> | 2008-03-23 04:09:59 +0300 |
---|---|---|
committer | matt <matt@59fd770c-687e-43c8-a1e3-f5a4ff64c105> | 2008-03-23 04:09:59 +0300 |
commit | 37d5deb35fe20a12756f02c439505dbaf5b4b792 (patch) | |
tree | a9fe7115469e4a71f4441914717b47224611a266 | |
parent | b1b5086f1d3aeb4b1c4965608527935f97590441 (diff) |
- fixed rendering of recursive dataTable (php / xml) eg. try http://piwik.org/demo/index.php?module=API&method=Actions.getActions&idSite=1&period=week&date=today&filter_column_recursive=label&filter_pattern_recursive=index&expanded=1&format=xml
- refs #33 work in progress
31 files changed, 401 insertions, 183 deletions
diff --git a/misc/download-count.txt b/misc/download-count.txt new file mode 100644 index 0000000000..b4e421d44f --- /dev/null +++ b/misc/download-count.txt @@ -0,0 +1,6 @@ +Count the download for 'last.zip' on the 20th March + +/var/log/apache2$ cat access.log | grep "20/Mar" | grep "last.zip" | awk '{print $1}' | sort | uniq | wc -l + + +Value to be compared with the one given by Piwik in Actions > Downloads
\ No newline at end of file diff --git a/modules/API/Request.php b/modules/API/Request.php index 36e3626755..389153d59b 100644 --- a/modules/API/Request.php +++ b/modules/API/Request.php @@ -427,7 +427,6 @@ class Piwik_API_Request // but by default it's not serialized if($this->caseRendererPHPSerialize( $defaultSerialize = 0)) { -// var_export($dataTable);exit; $dataTable = serialize($dataTable); } return $dataTable; diff --git a/modules/Archive.php b/modules/Archive.php index bb2740d333..7845dfbc0a 100644 --- a/modules/Archive.php +++ b/modules/Archive.php @@ -143,7 +143,7 @@ abstract class Piwik_Archive * If a idSubTable is given, the method will return the subTable of $name * * @param string $name - * @param int $idSubTable + * @param int $idSubTable or null if requesting the parent table * @return Piwik_DataTable * @throws exception If the value cannot be found */ @@ -155,7 +155,7 @@ abstract class Piwik_Archive * You can then access the subtables by using the Piwik_DataTable_Manager getTable() * * @param string $name - * @param int $idSubTable + * @param int $idSubTable or null if requesting the parent table * @return Piwik_DataTable */ abstract public function getDataTableExpanded($name, $idSubTable = null); diff --git a/modules/DataTable.php b/modules/DataTable.php index 828a2c3051..fe846dc022 100644 --- a/modules/DataTable.php +++ b/modules/DataTable.php @@ -121,6 +121,8 @@ require_once "DataTable/Manager.php"; * $XMLstring = $xmlOutput->getOutput(); * * + * @see Piwik_DataTable_Row A Piwik_DataTable is composed of Piwik_DataTable_Row + * * @package Piwik * @subpackage Piwik_DataTable * @@ -134,6 +136,14 @@ class Piwik_DataTable protected $indexNotUpToDate = false; protected $queuedFilters = array(); protected $rowsCountBeforeLimitFilter = 0; + + /** + * Defaults to false for performance reasons (most of the time we don't need recursive sorting so we save a looping over the dataTable) + * + * @var bool + */ + protected $enableRecursiveSort = false; + const MAXIMUM_DEPTH_LEVEL_ALLOWED = 20; public function __construct() @@ -145,6 +155,24 @@ class Piwik_DataTable { $this->indexNotUpToDate = true; usort( $this->rows, $functionCallback ); + + if($this->enableRecursiveSort === true) + { + foreach($this->getRows() as $row) + { + if(($idSubtable = $row->getIdSubDataTable()) !== null) + { + $table = Piwik_DataTable_Manager::getInstance()->getTable($idSubtable); + $table->enableRecursiveSort(); + $table->sort($functionCallback); + } + } + } + } + + public function enableRecursiveSort() + { + $this->enableRecursiveSort = true; } public function getRowsCountBeforeLimitFilter() @@ -322,6 +350,8 @@ class Piwik_DataTable /** * Returns the array of Piwik_DataTable_Row + * + * @return array of Piwik_DataTable_Row */ public function getRows() { diff --git a/modules/DataTable/Array.php b/modules/DataTable/Array.php index 4667868267..6828faf726 100644 --- a/modules/DataTable/Array.php +++ b/modules/DataTable/Array.php @@ -10,7 +10,8 @@ */ /** - * The DataTable_Array is a way to store an array of dataTable + * The DataTable_Array is a way to store an array of dataTable. + * The Piwik_DataTable_Array implements some of the features of the Piwik_DataTable such as queueFilter, getRowsCount. * * @package Piwik_DataTable */ diff --git a/modules/DataTable/Filter.php b/modules/DataTable/Filter.php index b40293fad3..561e3c3baa 100644 --- a/modules/DataTable/Filter.php +++ b/modules/DataTable/Filter.php @@ -12,10 +12,10 @@ /** * A filter is applied instantly to a given DataTable and can * - remove rows - * - change columns values - * - add/remove columns or details + * - change columns values (lowercase the strings, truncate, etc.) + * - add/remove columns or details (compute percentage values, add an 'icon' detail based on the label, etc.) * - add/remove/edit sub DataTable associated to some rows - * - whatever your imagination wants :) + * - whatever you can imagine * * The concept is very simple: the filter is given the DataTable * and can do whatever is necessary on the data (in the filter() method). diff --git a/modules/DataTable/Filter/Sort.php b/modules/DataTable/Filter/Sort.php index 4532a2f195..be69d05c60 100644 --- a/modules/DataTable/Filter/Sort.php +++ b/modules/DataTable/Filter/Sort.php @@ -11,7 +11,7 @@ /** * Sort the DataTable based on the value of column $columnToSort ordered by $order. - * + * Possible to specify a natural sorting (see php.net/natsort for details) * @package Piwik_DataTable * @subpackage Piwik_DataTable_Filter */ diff --git a/modules/DataTable/Manager.php b/modules/DataTable/Manager.php index c89ad9609e..81d1229d01 100644 --- a/modules/DataTable/Manager.php +++ b/modules/DataTable/Manager.php @@ -11,7 +11,8 @@ /** * The DataTable_Manager registers all the instanciated DataTable and provides an - * easy way to access them. + * easy way to access them. This is used to store all the DataTable during the archiving process. + * At the end of archiving, the ArchiveProcessing will read the stored datatable and record them in the DB. * * @package Piwik_DataTable */ @@ -21,6 +22,11 @@ class Piwik_DataTable_Manager protected function __construct() {} + /** + * Returns instance + * + * @return Piwik_DataTable_Manager + */ static public function getInstance() { if (self::$instance == null) @@ -30,12 +36,25 @@ class Piwik_DataTable_Manager } return self::$instance; } - + /** + * Array used to store the DataTable + * + * @var array + */ protected $tables = array(); + + /** + * Number of datatable currently stored in the array + * + * @var int + */ protected $count = 0; /** * Add a DataTable to the registry + * + * @param Piwik_DataTable + * @return int Number of tables registered in the manager (including the one just added) */ public function addTable( $table ) { @@ -50,6 +69,7 @@ class Piwik_DataTable_Manager * This method will not fetch the DataTable from the DB. * * @exception If the table can't be found + * @return Piwik_DataTable The table */ public function getTable( $idTable ) { @@ -66,7 +86,19 @@ class Piwik_DataTable_Manager } /** - * Delete all the registered DataTables + * Returns all the dataTable registered in the manager + * + * @return array of Piwik_DataTable + */ + public function getTables() + { + return $this->tables; + } + + /** + * Delete all the registered DataTables from the manager + * + * @return void */ public function deleteAll() { @@ -75,8 +107,10 @@ class Piwik_DataTable_Manager /** * Returns the number of DataTable currently registered. + * + * @return int */ - function count() + public function count() { return count($this->tables); } diff --git a/modules/DataTable/Renderer.php b/modules/DataTable/Renderer.php index f54bd03e90..12e0c34d2f 100644 --- a/modules/DataTable/Renderer.php +++ b/modules/DataTable/Renderer.php @@ -12,6 +12,9 @@ /** * A DataTable Renderer can produce an output given a DataTable object. * All new Renderers must be copied in DataTable/Renderer and added to the factory() method. + * To use a renderer, simply do: + * $render = new Piwik_DataTable_Renderer_Xml( $myTable ); + * echo $render; *
* @package Piwik_DataTable
* @subpackage Piwik_DataTable_Renderer @@ -20,6 +23,12 @@ abstract class Piwik_DataTable_Renderer { protected $table; + /** + * Builds the renderer. + * Works with any kind of DataTable if the renderer used handles this DataTable. + * + * @param Piwik_DataTable|Piwik_DataTable_Simple|Piwik_DataTable_Array $table to be rendered + */ function __construct($table = null) { if(!is_null($table)) @@ -29,12 +38,15 @@ abstract class Piwik_DataTable_Renderer } /** - * Computes the output and returns the string/binary + * Computes the dataTable output and returns the string/binary + * + * @return string */ abstract public function render(); /** * @see render() + * @return string */ public function __toString() { @@ -43,6 +55,8 @@ abstract class Piwik_DataTable_Renderer /** * Set the DataTable to be rendered + * + * @param Piwik_DataTable|Piwik_DataTable_Simple|Piwik_DataTable_Array $table to be rendered */ public function setTable($table) { @@ -57,7 +71,8 @@ abstract class Piwik_DataTable_Renderer /** * Returns the DataTable associated to the output format $name *
- * @exception If the renderer is unknown + * @throws exception If the renderer is unknown + * @return Piwik_DataTable_Renderer */ static public function factory( $name ) { diff --git a/modules/DataTable/Renderer/Csv.php b/modules/DataTable/Renderer/Csv.php index cf0516ecab..ea4c7920a1 100644 --- a/modules/DataTable/Renderer/Csv.php +++ b/modules/DataTable/Renderer/Csv.php @@ -19,6 +19,8 @@ require_once "DataTable/Renderer/Php.php"; * The default field delimiter string is a comma (,).
* Formatting and layout are ignored.
* + * Note that CSV output doesn't handle recursive dataTable. It will output only the first parent level of the tables. + * * @package Piwik_DataTable * @subpackage Piwik_DataTable_Renderer
* @@ -26,10 +28,34 @@ require_once "DataTable/Renderer/Php.php"; class Piwik_DataTable_Renderer_Csv extends Piwik_DataTable_Renderer { + /** + * Column separator + * + * @var string + */ public $separator = ','; + + /** + * Line end + * + * @var string + */ + public $lineEnd = "\n"; + + /** + * 'details' columns will be exported, prefixed by 'detail_' + * + * @var bool + */ public $exportDetail = true; + + /** + * idSubtable will be exported in a column called 'idsubdatatable' + * + * @var bool + */ public $exportIdSubtable = true; - public $lineEnd = "\n"; + function __construct($table = null) { diff --git a/modules/DataTable/Renderer/Html.php b/modules/DataTable/Renderer/Html.php index 0f60159564..a80230a137 100644 --- a/modules/DataTable/Renderer/Html.php +++ b/modules/DataTable/Renderer/Html.php @@ -11,6 +11,7 @@ /** * Simple HTML output + * Works with recursive DataTable (when a row can be associated with a subDataTable). * * @package Piwik_DataTable * @subpackage Piwik_DataTable_Renderer diff --git a/modules/DataTable/Renderer/Json.php b/modules/DataTable/Renderer/Json.php index bb8189c113..2a91b754e4 100644 --- a/modules/DataTable/Renderer/Json.php +++ b/modules/DataTable/Renderer/Json.php @@ -11,7 +11,8 @@ require_once "DataTable/Renderer/Php.php";
/** - * JSON export. Using the php 5.2 feature json_encode + * JSON export. Using the php 5.2 feature json_encode. + * Works with recursive DataTable (when a row can be associated with a subDataTable). * * @package Piwik_DataTable * @subpackage Piwik_DataTable_Renderer diff --git a/modules/DataTable/Renderer/Php.php b/modules/DataTable/Renderer/Php.php index 5a6718eb6a..3027b8849b 100644 --- a/modules/DataTable/Renderer/Php.php +++ b/modules/DataTable/Renderer/Php.php @@ -10,16 +10,20 @@ */
/** - * Returns the equivalent PHP array of the DataTable. + * Returns the equivalent PHP array for a given DataTable. * You can specify in the constructor if you want the serialized version.
* Please note that by default it will produce a flat version of the array.
- * See the method flatRender() for details. + * See the method flatRender() for details. @see flatRender(); + * + * Works with recursive DataTable (when a row can be associated with a subDataTable). * * @package Piwik_DataTable * @subpackage Piwik_DataTable_Renderer */ class Piwik_DataTable_Renderer_Php extends Piwik_DataTable_Renderer { + protected $serialize; + public function __construct($table = null, $serialize = true) { parent::__construct($table); @@ -56,7 +60,7 @@ class Piwik_DataTable_Renderer_Php extends Piwik_DataTable_Renderer * @return array Php array representing the 'flat' version of the datatable
*
*/
- public function flatRender( $dataTable = null )
+ public function flatRender( $dataTable = null, $doRenderSubTablesIfAvailable = true )
{ if(is_null($dataTable)) { @@ -73,7 +77,6 @@ class Piwik_DataTable_Renderer_Php extends Piwik_DataTable_Renderer $flatArray[$keyName] = $this->flatRender($table); $this->serialize = $serializeSave; } -// var_dump($flatArray); } // A DataTable_Simple is already flattened so no need to do some crazy stuff to convert it
@@ -87,16 +90,12 @@ class Piwik_DataTable_Renderer_Php extends Piwik_DataTable_Renderer { $flatArray = current($flatArray); } -// elseif(count($flatArray) == 0) -// { -// $flatArray = null; -// } }
// A normal DataTable needs to be handled specifically
else
{
- $array = $this->renderTable($dataTable); + $array = $this->renderTable($dataTable, $doRenderSubTablesIfAvailable); $flatArray = $this->flattenArray($array);
}
@@ -164,8 +163,6 @@ class Piwik_DataTable_Renderer_Php extends Piwik_DataTable_Renderer return $array; } - protected $serialize;
-
protected function renderTable($table, $doRenderSubTablesIfAvailable = false) { diff --git a/modules/DataTable/Renderer/Rss.php b/modules/DataTable/Renderer/Rss.php index e7f5a27629..e09da181ab 100644 --- a/modules/DataTable/Renderer/Rss.php +++ b/modules/DataTable/Renderer/Rss.php @@ -10,7 +10,9 @@ */ /** - * RSS Feed + * RSS Feed. + * The RSS renderer can be used only on Piwik_DataTable_Array that are arrays of Piwik_DataTable. + * A RSS feed contains one dataTable per element in the Piwik_DataTable_Array. * * @package Piwik_DataTable * @subpackage Piwik_DataTable_Renderer diff --git a/modules/DataTable/Renderer/Xml.php b/modules/DataTable/Renderer/Xml.php index 25368758a3..ec6f6cff06 100644 --- a/modules/DataTable/Renderer/Xml.php +++ b/modules/DataTable/Renderer/Xml.php @@ -11,7 +11,11 @@ require_once "DataTable/Renderer/Php.php";
/** - * XML export + * XML export of a given DataTable. + * See the tests cases for more information about the XML format (/tests/modules/DataTable/Renderer.test.php) + * Or have a look at the API calls examples. + * + * Works with recursive DataTable (when a row can be associated with a subDataTable). * * @package Piwik_DataTable * @subpackage Piwik_DataTable_Renderer @@ -193,6 +197,12 @@ class Piwik_DataTable_Renderer_Xml extends Piwik_DataTable_Renderer $out .= $prefixLine."\t<row>\n"; foreach($row as $name => $value) { + // handle the recursive dataTable case by XML outputting the recursive table + if(is_array($value)) + { + $value = "\n".$this->renderDataTable($value, $prefixLine."\t\t"); + $value .= $prefixLine."\t\t"; + } $out .= $prefixLine."\t\t<$name>$value</$name>\n"; } $out .= $prefixLine."\t</row>\n"; diff --git a/modules/DataTable/Row.php b/modules/DataTable/Row.php index 0b91ca29f7..329d8600ab 100644 --- a/modules/DataTable/Row.php +++ b/modules/DataTable/Row.php @@ -10,11 +10,12 @@ */
/** - * A DataTable is composed by rows. - * A row is composed by + * A DataTable is composed of rows. + * + * A row is composed of: * - columns often at least a 'label' column containing the description * of the row, and some numeric values ('nb_visits', etc.) - * - details: other information never to be shown as "columns") + * - details: other information never to be shown as 'columns' * - idSubtable: a row can be linked to a SubTable * * IMPORTANT: Make sure that the column named 'label' contains at least one non-numeric character. @@ -27,7 +28,16 @@ */ class Piwik_DataTable_Row { - // Row content + /** + * This array contains the row information: + * - array indexed by self::COLUMNS contains the columns, pairs of (column names, value) + * - (optional) array indexed by self::DETAILS contains the details, pairs of (detail names, value) + * - (optional) integer indexed by self::DATATABLE_ASSOCIATED contains the ID of the Piwik_DataTable associated to this row. + * This ID can be used to read the DataTable from the DataTable_Manager. + * + * @var array + * @see constructor for more information + */ public $c = array(); const COLUMNS = 0; @@ -36,20 +46,20 @@ class Piwik_DataTable_Row /** - * Very efficient load of the Row structure from a well structured php array + * Efficient load of the Row structure from a well structured php array * * @param array The row array has the structure * array( * Piwik_DataTable_Row::COLUMNS => array( - * 0 => 1554, - * 1 => 42, - * 2 => 657, - * 3 => 155744, + * 'label' => 'Piwik', + * 'column1' => 42, + * 'visits' => 657, + * 'time_spent' => 155744, * ), * Piwik_DataTable_Row::DETAILS => array( * 'logo' => 'test.png' * ), - * Piwik_DataTable_Row::DATATABLE_ASSOCIATED => #DataTable object // numeric idDataTable + * Piwik_DataTable_Row::DATATABLE_ASSOCIATED => #Piwik_DataTable object (but in the row only the ID will be stored) * ) */ public function __construct( $row = array() ) @@ -84,10 +94,15 @@ class Piwik_DataTable_Row unset($idSubtable); } } -
+ + /** + * Applys a basic rendering to the Row and returns the output + * + * @return string characterizing the row. Example: - 1 ['label' => 'piwik', 'nb_uniq_visitors' => 1685, 'nb_visits' => 1861, 'nb_actions' => 2271, 'max_actions' => 13, 'sum_visit_length' => 920131, 'bounce_count' => 1599] [] [idsubtable = 1375] + */
public function __toString()
{
- $columns=array();
+ $columns = array();
foreach($this->getColumns() as $column => $value)
{
if(is_string($value)) $value = "'$value'";
@@ -107,12 +122,25 @@ class Piwik_DataTable_Row return $output;
}
+ /** + * Deletes the given column + * + * @param string Column name + * @return bool True on success, false if the column didn't exist + */ public function deleteColumn( $name ) { + if(!isset($this->c[self::COLUMNS][$name])) + { + return false; + } unset($this->c[self::COLUMNS][$name]); + return true; } + /** * Returns the given column + * * @param string Column name * @return mixed|false The column value */ @@ -127,6 +155,7 @@ class Piwik_DataTable_Row /** * Returns the given detail + * * @param string Detail name * @return mixed|false The detail value */ @@ -140,9 +169,9 @@ class Piwik_DataTable_Row } /** - * Returns the array of columns + * Returns the array containing all the columns * - * @return array array( + * @return array Example: array( * 'column1' => VALUE, * 'label' => 'www.php.net' * 'nb_visits' => 15894, @@ -154,9 +183,9 @@ class Piwik_DataTable_Row } /** - * Returns the array of details + * Returns the array containing all the details * - * @return array array( + * @return array Example: array( * 'logo' => 'images/logo/www.google.png', * 'url' => 'www.google.com' * ) @@ -180,8 +209,10 @@ class Piwik_DataTable_Row /** * Sums a DataTable to this row subDataTable. * If this row doesn't have a SubDataTable yet, we create a new one. - * Then we add the values of the given DataTable to this row's DataTable - * @see addDataTable() for the summing algorithm + * Then we add the values of the given DataTable to this row's DataTable. + * + * @param Piwik_DataTable Table to sum to this row's subDatatable + * @see Piwik_DataTable::addDataTable() for the algorithm used for the sum */ public function sumSubtable(Piwik_DataTable $subTable) { @@ -198,32 +229,30 @@ class Piwik_DataTable_Row $thisSubTable->addDataTable($subTable); } - - - protected function checkNoSubTable() - { - if(!is_null($this->c[self::DATATABLE_ASSOCIATED])) - { - throw new Exception("Adding a subtable to the row, but it already has a subtable associated."); - } - } /** * Set a DataTable to be associated to this row. * If the row already has a DataTable associated to it, throws an Exception. + * + * @param Piwik_DataTable DataTable to associate to this row * @throws Exception * */ public function addSubtable(Piwik_DataTable $subTable) { - $this->checkNoSubTable(); + if(!is_null($this->c[self::DATATABLE_ASSOCIATED])) + { + throw new Exception("Adding a subtable to the row, but it already has a subtable associated."); + } $this->c[self::DATATABLE_ASSOCIATED] = $subTable->getId(); } /** * Set a DataTable to this row. If there is already * a DataTable associated, it is simply overwritten. + * + * @param Piwik_DataTable DataTable to associate to this row */ public function setSubtable(Piwik_DataTable $subTable) { @@ -231,7 +260,8 @@ class Piwik_DataTable_Row } /** - * Set all the columns at once. + * Set all the columns at once. Overwrites previously set columns. + * * @param array array( * 'label' => 'www.php.net' * 'nb_visits' => 15894, @@ -243,7 +273,10 @@ class Piwik_DataTable_Row } /** - * Set the $value value to the column named $name + * Set the value $value to the column called $name. + * + * @param string $name of the column to set + * @param mixed $value of the column to set */ public function setColumn($name, $value) { @@ -260,7 +293,10 @@ class Piwik_DataTable_Row } /** - * Add a new column to the row. If the column already exist, throw an exception + * Add a new column to the row. If the column already exists, throws an exception + * + * @param string $name of the column to add + * @param mixed $value of the column to set * @throws Exception */ public function addColumn($name, $value) @@ -274,7 +310,10 @@ class Piwik_DataTable_Row /** - * Add a new detail to the row. If the column already exist, throw an exception + * Add a new detail to the row. If the column already exists, throws an exception. + * + * @param string $name of the detail to add + * @param mixed $value of the detail to set * @throws Exception */ public function addDetail($name, $value) @@ -287,14 +326,15 @@ class Piwik_DataTable_Row } /** - * Add the given $row columns values to the existing row' columns values. - * It will take in consideration only the int or float values of $row. + * Sums the given $row columns values to the existing row' columns values. + * It will sum only the int or float values of $row. + * It will not sum the column 'label' even if it has a numeric value. * * If a given column doesn't exist in $this then it is added with the value of $row. * If the column already exists in $this then we have * this.columns[idThisCol] += $row.columns[idThisCol] */ - public function sumRow( $rowToSum ) + public function sumRow( Piwik_DataTable_Row $rowToSum ) { foreach($rowToSum->getColumns() as $name => $value) { @@ -302,7 +342,7 @@ class Piwik_DataTable_Row && Piwik::isNumeric($value)) { $current = $this->getColumn($name); - if($current==false) + if($current === false) { $current = 0; } @@ -317,9 +357,14 @@ class Piwik_DataTable_Row * * Two rows are equal * - if they have exactly the same columns / details - * - if they have a subDataTable associated and that both of them are exactly the same. + * - if they have a subDataTable associated, then we check that both of them are the same. + * + * @param Piwik_DataTable_Row row1 to compare + * @param Piwik_DataTable_Row row2 to compare + * + * @return bool */ - static public function isEqual( $row1, $row2 ) + static public function isEqual( Piwik_DataTable_Row $row1, Piwik_DataTable_Row $row2 ) { //same columns $cols1 = $row1->getColumns(); diff --git a/modules/DataTable/Row/DataTableSummary.php b/modules/DataTable/Row/DataTableSummary.php index 20675c70c4..8f34a79655 100644 --- a/modules/DataTable/Row/DataTableSummary.php +++ b/modules/DataTable/Row/DataTableSummary.php @@ -15,7 +15,7 @@ * - for each numeric column, the returned "summary" column is the sum of all the subRows * - for every other column, it is ignored and will not be in the "summary row" * - * @see Piwik_DataTable_Row::sumRow() for more information on the algorith + * @see Piwik_DataTable_Row::sumRow() for more information on the algorithm * * @package Piwik_DataTable * @subpackage Piwik_DataTable_Row diff --git a/modules/DataTable/Simple.php b/modules/DataTable/Simple.php index 0ef5215a3d..d369d48fe0 100644 --- a/modules/DataTable/Simple.php +++ b/modules/DataTable/Simple.php @@ -10,27 +10,19 @@ */
/** - * The DataTable_Simple is used to provide a very simple way to create simple DataGrid. + * The DataTable_Simple is used to provide an easy way to create simple DataGrid. + * A DataTable_Simple actually is a DataTable with 2 columns: 'label' and 'value'. * - * A DataTable Simple basically is an array of name => value - * - * Returning a DataTable_Simple from a plugin API Call has huge advantages: + * It is usually best to return a DataTable_Simple instead of + * a PHP array (or other custom data structure) in API methods: * - the generic filters can be applied automatically (offset, limit, pattern search, sort, etc.) * - the renderer can be applied (XML, PHP, HTML, etc.) - * * So you don't have to write specific renderer for your data, it is already available in all the formats supported natively by Piwik. * - * NB: A DataTable_Simple actually is a DataTable with 2 columns: 'label' and 'value'. - * * @package Piwik_DataTable */ class Piwik_DataTable_Simple extends Piwik_DataTable { - public function __construct() - { - parent::__construct(); - } - /** * Loads in the DataTable the array information * @param array Array containing the rows information @@ -38,6 +30,7 @@ class Piwik_DataTable_Simple extends Piwik_DataTable * 'Label row 1' => Value row 1, * 'Label row 2' => Value row 2, * ) + * @return void */ function loadFromArray($array) { @@ -50,7 +43,12 @@ class Piwik_DataTable_Simple extends Piwik_DataTable } } - + /** + * Returns the 'value' column of the row that has a label '$label'. + * + * @param string Label of the row we want the value + * @return false|mixed The 'value' column of the row labelled $label + */ function getColumn( $label ) { $row = $this->getRowFromLabel($label); diff --git a/modules/Log/APICall.php b/modules/Log/APICall.php index 8ca7e5115a..a14df78221 100644 --- a/modules/Log/APICall.php +++ b/modules/Log/APICall.php @@ -14,6 +14,7 @@ * Class used to log all the API Calls information (class / method / parameters / returned value / time spent) * * @package Piwik_Log + * @subpackage Piwik_Log_APICall */ class Piwik_Log_APICall extends Piwik_Log { diff --git a/modules/Log/Error.php b/modules/Log/Error.php index 020d9cd007..f4346efe1f 100644 --- a/modules/Log/Error.php +++ b/modules/Log/Error.php @@ -14,6 +14,7 @@ * Class used to log an error event. * * @package Piwik_Log + * @subpackage Piwik_Log_Error */ class Piwik_Log_Error extends Piwik_Log { diff --git a/modules/Log/Exception.php b/modules/Log/Exception.php index 1153e947dd..e5a47e827f 100644 --- a/modules/Log/Exception.php +++ b/modules/Log/Exception.php @@ -13,8 +13,10 @@ require_once "Log.php"; /** * Class used to log an exception event. + * Displays the exception with a user friendly error message, suggests to get support from piwik.org * * @package Piwik_Log + * @subpackage Piwik_Log_Exception */ class Piwik_Log_Exception extends Piwik_Log { diff --git a/modules/Log/Message.php b/modules/Log/Message.php index 87ce18db0c..07f19c442a 100644 --- a/modules/Log/Message.php +++ b/modules/Log/Message.php @@ -14,6 +14,7 @@ * Class used to log a standard message event. * * @package Piwik_Log + * @subpackage Piwik_Log_Message */ class Piwik_Log_Message extends Piwik_Log { diff --git a/modules/LogStats/Action.php b/modules/LogStats/Action.php index 9f72043c30..5edcdee36e 100644 --- a/modules/LogStats/Action.php +++ b/modules/LogStats/Action.php @@ -16,55 +16,18 @@ * This class is used to build the Action Name (which can be built from the URL, * or can be directly specified in the JS code, etc.). * It also saves the Action when necessary in the DB. - * - * - * About the Action concept - * ------------------------------------ + * + * About the Action concept: * - An action is defined by a name. * - The name can be specified in the JS Code in the variable 'action_name' + * For example you can decide to use the javascript value document.title as an action_name + * - If the name is not specified, we use the URL(path+query) to build a default name. + * For example for "http://piwik.org/test/my_page/test.html" + * the name would be "test/my_page/test.html" + * - If the name is empty we set it to default_action_name found in global.ini.php * - Handling UTF8 in the action name - * PLUGIN_IDEA - An action is associated to URLs and link to the URL from the interface - * PLUGIN_IDEA - An action hit by a visitor is associated to the HTML title of the page that triggered the action - * - * + If the name is not specified, we use the URL(path+query) to build a default name. - * For example for "http://piwik.org/test/my_page/test.html" - * the name would be "test/my_page/test.html" - * - * We make sure it is clean and displayable. - * If the name is empty we set it to a default name. - * - * Specifications - * - * - Download tracking - * - * * MANUAL Download tracking - * download = http://piwik.org/hellokity.zip - * (name = dir1/file alias name) - * - * * AUTOMATIC Download tracking for a known list of file extensions. - * Make a hit to the piwik.php with the parameter: - * download = http://piwik.org/hellokity.zip - * - * When 'name' is not specified, - * if AUTOMATIC and if anchor not empty => name = link title anchor - * else name = path+query of the URL - * Ex: myfiles/beta.zip - * - * - External link tracking - * - * * MANUAL External link tracking - * outlink = http://amazon.org/test - * (name = the big partners / amazon) - * - * * AUTOMATIC External link tracking - * When a link is not detected as being part of the same website - * AND when the url extension is not detected as being a file download - * outlink = http://amazon.org/test - * - * When 'name' is not specified, - * if AUTOMATIC and if anchor not empty => name = link title anchor - * else name = URL - * Ex: http://amazon.org/test + * PLUGIN_IDEA - An action is associated to URLs and link to the URL from the reports (currently actions do not link to the url of the pages) + * PLUGIN_IDEA - An action hit by a visitor is associated to the HTML title of the page that triggered the action and this HTML title is displayed in the interface * * * @package Piwik_LogStats @@ -84,7 +47,7 @@ class Piwik_LogStats_Action const TYPE_OUTLINK = 2; /** - * @param Piwik_LogStats_Db object + * @param Piwik_LogStats_Db Database object to be used */ function __construct( $db ) { @@ -105,11 +68,14 @@ class Piwik_LogStats_Action } /** - * Generate the name of the action from the URL or the specified name. - * See the class description for more information. + * Generates the name of the action from the URL or the specified name. + * Sets the name as $this->finalActionName + * + * @return void */ private function generateInfo() { + $actionName = ''; if(!empty($this->downloadUrl)) { $this->actionType = self::TYPE_DOWNLOAD; @@ -212,6 +178,8 @@ class Piwik_LogStats_Action } /** + * Sets the attribute $idAction based on $finalActionName and $actionType. + * * @see getActionId() */ private function loadActionId() @@ -223,7 +191,9 @@ class Piwik_LogStats_Action $idAction = $this->db->fetch(" SELECT idaction FROM ".$this->db->prefixTable('log_action') - ." WHERE name = ? AND type = ?", array($name, $type) ); + ." WHERE name = ? AND type = ?", + array($name, $type) + ); // the action name has not been found, create it if($idAction === false) diff --git a/modules/LogStats/Config.php b/modules/LogStats/Config.php index bac16e7cd4..fc53b58b2e 100644 --- a/modules/LogStats/Config.php +++ b/modules/LogStats/Config.php @@ -12,16 +12,24 @@ /** * Simple class to access the configuration file * - * This is essentially a very simple version of Zend_Config that we wrote - * because of performance concerns. + * This is essentially a simple version of Zend_Config that we wrote + * because of performance reasons. * The LogStats module can't afford a dependency with the Zend_Framework. * + * It's using the php.net/parse_ini_file function to parse the configuration files. + * It can be used to access both user config.ini.php and piwik global.ini.php config file. + * * @package Piwik_LogStats */ class Piwik_LogStats_Config { static private $instance = null; + /** + * Returns singleton + * + * @return Piwik_LogStats_Config + */ static public function getInstance() { if (self::$instance == null) @@ -32,6 +40,11 @@ class Piwik_LogStats_Config return self::$instance; } + /** + * Contains configuration files values + * + * @var array + */ public $config = array(); private function __construct() @@ -42,6 +55,14 @@ class Piwik_LogStats_Config $this->configGlobal = parse_ini_file($pathIniFileGlobal, true); } + /** + * Magic get methods catching calls to $config->var_name + * Returns the value if found in the + * + * @param string $name + * @return mixed The value requested, usually a string + * @throws exception if the value requested not found in both files + */ public function __get( $name ) { if(isset($this->configUser[$name])) diff --git a/modules/LogStats/Db.php b/modules/LogStats/Db.php index 76959055a3..9a04f5d73b 100644 --- a/modules/LogStats/Db.php +++ b/modules/LogStats/Db.php @@ -11,7 +11,8 @@ /** * Simple database PDO wrapper. - * We can't afford to have a dependency with the Zend_Db module in the LogStats module. + * We can't afford to have a dependency with the Zend_Db module in LogStats. + * We wrote this simple class * * @package Piwik_LogStats */ @@ -29,16 +30,16 @@ class Piwik_LogStats_Db /** * Builds the DB object */ - public function __construct( $host, $username, $password, $dbname) + public function __construct( $host, $username, $password, $dbname, $driverName = 'mysql') { - $this->dsn = "mysql:dbname=$dbname;host=$host"; + $this->dsn = $driverName.":dbname=$dbname;host=$host"; $this->username = $username; $this->password = $password; } /** - * Returns true if the profiler is enabled + * Returns true if the SQL profiler is enabled * Only used by the unit test that tests that the profiler is off on a production server * * @return bool @@ -49,7 +50,7 @@ class Piwik_LogStats_Db } /** - * Enables the profiling. + * Enables the SQL profiling. * For each query, saves in the DB the time spent on this query. * Very useful to see the slow query under heavy load. * You can then use Piwik::printLogStatsSQLProfiling(); @@ -59,8 +60,9 @@ class Piwik_LogStats_Db { self::$profiling = true; } + /** - * Disables the profiling logging. + * Disables the SQL profiling logging. */ static public function disableProfiling() { @@ -69,6 +71,8 @@ class Piwik_LogStats_Db /** * Connects to the DB + * + * @throws Exception if there was an error connecting the DB */ public function connect() { @@ -76,7 +80,15 @@ class Piwik_LogStats_Db $pdoConnect = new PDO($this->dsn, $this->username, $this->password); $pdoConnect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); $this->connection = $pdoConnect; + + // we erase the password from this object "just in case" it could be printed + $this->password = ''; } catch (PDOException $e) { + + // we erase the password from this object "just in case" it could be printed + $this->password = ''; + + // we don't throw the PDO Exception directly as it may contain sensitive information throw new Exception("Error connecting database: ".$e->getMessage()); } } @@ -97,10 +109,14 @@ class Piwik_LogStats_Db } /** - * Returns an array containing all the rows of a query result. + * Returns an array containing all the rows of a query result, using optional bound parameters. + * + * @param string Query + * @param array Parameters to bind * @see also query() + * @throws Exception if an exception occured */ - public function fetchAll( $query, $parameters ) + public function fetchAll( $query, $parameters = array() ) { try { $sth = $this->query( $query, $parameters ); @@ -111,10 +127,15 @@ class Piwik_LogStats_Db } /** - * Returns the first row of a query result. - * @see query() + * Returns the first row of a query result, using optional bound parameters. + * + * @param string Query + * @param array Parameters to bind + * @see also query() + * + * @throws Exception if an exception occured */ - public function fetch( $query, $parameters ) + public function fetch( $query, $parameters = array() ) { try { $sth = $this->query( $query, $parameters ); @@ -125,10 +146,12 @@ class Piwik_LogStats_Db } /** - * Executes a query with bind parameters + * Executes a query, using optional bound parameters. * * @param string Query * @param array Parameters to bind + * + * @throw Exception if an exception occured */ public function query($query, $parameters = array()) { @@ -161,6 +184,7 @@ class Piwik_LogStats_Db /** * Returns the last inserted ID in the DB * Wrapper of PDO::lastInsertId() + * * @return int */ public function lastInsertId() @@ -169,7 +193,7 @@ class Piwik_LogStats_Db } /** - * When destroyed, log the SQL profiling information + * When destroyed, if SQL profiled enabled, logs the SQL profiling information */ public function __destruct() { diff --git a/modules/LogStats/Generator.php b/modules/LogStats/Generator.php index e869a18793..c84ecce935 100644 --- a/modules/LogStats/Generator.php +++ b/modules/LogStats/Generator.php @@ -13,6 +13,10 @@ * Class used to generate fake visits. * Useful to test performances, general functional testing, etc. * + * Objective: + * Generate thousands of visits / actions per visitor using + * a single request to misc/generateVisits.php + * * Requirements of the visits generator script. Fields that can be edited: * - url => campaigns * - newsletter @@ -28,12 +32,11 @@ * - action_name * - HTML title * - * Objective: - * Generate thousands of visits / actions per visitor * * @package Piwik_LogStats * - * "Le Generator, il est trop Fort!" + * "Le Generator, il est trop Fort!" + * - Random fan */ class Piwik_LogStats_Generator diff --git a/modules/ViewDataTable.php b/modules/ViewDataTable.php index d767cdfb3e..8cf17db696 100644 --- a/modules/ViewDataTable.php +++ b/modules/ViewDataTable.php @@ -29,6 +29,9 @@ abstract class Piwik_ViewDataTable protected $JSsortEnabled = true; protected $showFooter = true; + + protected $recursiveDataTableLoad = false; + protected $currentControllerAction; protected $currentControllerName; @@ -40,10 +43,7 @@ abstract class Piwik_ViewDataTable public $dataTable; // data table protected $moduleNameAndMethod; - - // do we need all the children of the datatables? - protected $recursiveDataTableLoad = false; - + protected $variablesDefault = array(); protected $idSubtable = false; @@ -216,7 +216,7 @@ abstract class Piwik_ViewDataTable { // if we request a subDataTable the $this->currentControllerAction DIV ID is already there in the page // we make the DIV ID really unique by appending the ID of the subtable requested - if( $this->idSubtable != false) + if( $this->idSubtable !== false) { $uniqIdTable = 'subDataTable_' . $this->idSubtable; } @@ -314,12 +314,14 @@ abstract class Piwik_ViewDataTable return $javascriptVariablesToSet; } - protected function loadDataTableFromAPI( $idSubtable = false) - { - if($idSubtable === false) - { - $idSubtable = $this->idSubtable; - } + /** + * Function called by the ViewDataTable objects in order to fetch data from the API. + * They must set $this->moduleNameAndMethod before (using the $this->init() method). + * + * + */ + protected function loadDataTableFromAPI() + { // we prepare the string to give to the API Request // we setup the method and format variable // - we request the method to call to get this specific DataTable @@ -332,12 +334,6 @@ abstract class Piwik_ViewDataTable $requestString .= '&expanded=1'; } - // if a subDataTable is requested we add the variable to the API request string - if( $idSubtable != false) - { - $requestString .= '&this->idSubtable='.$idSubtable; - } - $toSetEventually = array( 'filter_limit', 'filter_sort_column', @@ -357,15 +353,13 @@ abstract class Piwik_ViewDataTable $requestString .= '&'.$varToSet.'='.$value; } } -// echo $requestString;exit; + // We finally make the request to the API $request = new Piwik_API_Request($requestString); // and get the DataTable structure $dataTable = $request->process(); -// echo $dataTable;exit; - $this->dataTable = $dataTable; } diff --git a/modules/ViewDataTable/Html.php b/modules/ViewDataTable/Html.php index e67352b47b..0411af8320 100644 --- a/modules/ViewDataTable/Html.php +++ b/modules/ViewDataTable/Html.php @@ -133,8 +133,6 @@ class Piwik_ViewDataTable_Html extends Piwik_ViewDataTable return false; } - - public function setSearchRecursive() { $this->variablesDefault['search_recursive'] = true; @@ -1,4 +1,4 @@ -<?php
+<?php
/**
* Piwik - Open source web analytics
* @@ -51,20 +51,17 @@ require_once "LogStats/Visit.php"; $GLOBALS['DEBUGPIWIK'] = false; - if($GLOBALS['DEBUGPIWIK'] === true) { date_default_timezone_set(date_default_timezone_get()); - /** - * Error / exception handling functions - */ require_once PIWIK_INCLUDE_PATH . "/modules/ErrorHandler.php"; require_once PIWIK_INCLUDE_PATH . "/modules/ExceptionHandler.php"; set_error_handler('Piwik_ErrorHandler'); set_exception_handler('Piwik_ExceptionHandler'); + printDebug($_GET); } + ob_start(); -printDebug($_GET); $process = new Piwik_LogStats; $process->main(); ob_end_flush(); diff --git a/plugins/Actions/API.php b/plugins/Actions/API.php index 9058ae51ed..84263b3d38 100644 --- a/plugins/Actions/API.php +++ b/plugins/Actions/API.php @@ -48,7 +48,8 @@ class Piwik_Actions_API extends Piwik_Apiable if($expanded) { - $dataTable = $archive->getDataTableExpanded($name, $idSubtable); + $dataTable = $archive->getDataTableExpanded($name, $idSubtable); + $dataTable->enableRecursiveSort(); } else { diff --git a/tests/modules/DataTable/Renderer.test.php b/tests/modules/DataTable/Renderer.test.php index 0f85c0272e..6d84d18a87 100644 --- a/tests/modules/DataTable/Renderer.test.php +++ b/tests/modules/DataTable/Renderer.test.php @@ -40,12 +40,21 @@ class Test_Piwik_DataTable_Renderer extends UnitTestCase */ protected function getDataTableTest() { + $arraySubTableForRow2 = array ( + array ( Piwik_DataTable_Row::COLUMNS => array( 'label' => 'sub1', 'count' => 1) ), + array ( Piwik_DataTable_Row::COLUMNS => array( 'label' => 'sub2', 'count' => 2) ), + ); + $subDataTableForRow2 = new Piwik_DataTable(); + $subDataTableForRow2->loadFromArray($arraySubTableForRow2); + + $subtable = $array = array ( array ( Piwik_DataTable_Row::COLUMNS => array( 'label' => 'Google', 'nb_uniq_visitors' => 11, 'nb_visits' => 11, 'nb_actions' => 17, 'max_actions' => '5', 'sum_visit_length' => 517, 'bounce_count' => 9), Piwik_DataTable_Row::DETAILS => array('url' => 'http://www.google.com', 'logo' => './plugins/Referers/images/searchEngines/www.google.com.png'), ), array ( Piwik_DataTable_Row::COLUMNS => array( 'label' => 'Yahoo!', 'nb_uniq_visitors' => 15, 'nb_visits' => 151, 'nb_actions' => 147, 'max_actions' => '50', 'sum_visit_length' => 517, 'bounce_count' => 90), - Piwik_DataTable_Row::DETAILS => array('url' => 'http://www.yahoo.com', 'logo' => './plugins/Referers/images/searchEngines/www.yahoo.com.png'), + Piwik_DataTable_Row::DETAILS => array('url' => 'http://www.yahoo.com', 'logo' => './plugins/Referers/images/searchEngines/www.yahoo.com.png'), + Piwik_DataTable_Row::DATATABLE_ASSOCIATED => $subDataTableForRow2, ) ); $dataTable = new Piwik_DataTable(); @@ -116,9 +125,22 @@ class Test_Piwik_DataTable_Renderer extends UnitTestCase <bounce_count>90</bounce_count> <url>http://www.yahoo.com</url> <logo>./plugins/Referers/images/searchEngines/www.yahoo.com.png</logo> + <idsubdatatable>1</idsubdatatable> + <subtable> + <row> + <label>sub1</label> + <count>1</count> + </row> + <row> + <label>sub2</label> + <count>2</count> + </row> + </subtable> </row> </result>'; - $this->assertEqual( $expected,$render->render()); + $rendered = $render->render(); + + $this->assertEqual( $expected,$rendered); } function test_XML_test2() @@ -216,9 +238,11 @@ bounce_count,44'; { $dataTable = $this->getDataTableTest(); $render = new Piwik_DataTable_Renderer_Json($dataTable); - $expected = '[{"label":"Google","nb_uniq_visitors":11,"nb_visits":11,"nb_actions":17,"max_actions":"5","sum_visit_length":517,"bounce_count":9,"url":"http:\/\/www.google.com","logo":".\/plugins\/Referers\/images\/searchEngines\/www.google.com.png"},{"label":"Yahoo!","nb_uniq_visitors":15,"nb_visits":151,"nb_actions":147,"max_actions":"50","sum_visit_length":517,"bounce_count":90,"url":"http:\/\/www.yahoo.com","logo":".\/plugins\/Referers\/images\/searchEngines\/www.yahoo.com.png"}]'; + $expected = '[{"label":"Google","nb_uniq_visitors":11,"nb_visits":11,"nb_actions":17,"max_actions":"5","sum_visit_length":517,"bounce_count":9,"url":"http:\/\/www.google.com","logo":".\/plugins\/Referers\/images\/searchEngines\/www.google.com.png"},{"label":"Yahoo!","nb_uniq_visitors":15,"nb_visits":151,"nb_actions":147,"max_actions":"50","sum_visit_length":517,"bounce_count":90,"url":"http:\/\/www.yahoo.com","logo":".\/plugins\/Referers\/images\/searchEngines\/www.yahoo.com.png","idsubdatatable":13,"subtable":[{"label":"sub1","count":1},{"label":"sub2","count":2}]}]'; - $this->assertEqual( $expected,$render->render()); + $rendered = $render->render(); + + $this->assertEqual( $expected,$rendered); } function test_JSON_test2() { @@ -281,9 +305,25 @@ bounce_count,44'; 'bounce_count' => 90, 'url' => 'http://www.yahoo.com', 'logo' => './plugins/Referers/images/searchEngines/www.yahoo.com.png', + 'idsubdatatable' => 19, + 'subtable' => + array ( + 0 => + array ( + 'label' => 'sub1', + 'count' => 1, + ), + 1 => + array ( + 'label' => 'sub2', + 'count' => 2, + ), + ), ), )); - $this->assertEqual( $expected,$render->render()); + $rendered = $render->render(); +// var_export(unserialize($rendered)); + $this->assertEqual( $expected,$rendered); } function test_PHP_test2() { |