Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/Plugin/Report.php12
-rw-r--r--core/Translate.php14
-rw-r--r--plugins/CoreConsole/Commands/GenerateReport.php280
-rw-r--r--plugins/ExamplePlugin/API.php16
-rw-r--r--plugins/ExamplePlugin/Reports/Base.php19
-rw-r--r--plugins/ExamplePlugin/Reports/GetExampleReport.php111
-rw-r--r--plugins/Feedback/API.php16
7 files changed, 452 insertions, 16 deletions
diff --git a/core/Plugin/Report.php b/core/Plugin/Report.php
index 0fa4965395..61b7436873 100644
--- a/core/Plugin/Report.php
+++ b/core/Plugin/Report.php
@@ -40,7 +40,7 @@ class Report
protected $parameters = null;
/**
- * @var \Piwik\Plugin\VisitDimension
+ * @var \Piwik\Plugin\VisitDimension|\Piwik\Plugin\ActionDimension
*/
protected $dimension;
protected $documentation;
@@ -234,6 +234,16 @@ class Report
return Piwik::translate($this->category);
}
+ public function getDimension()
+ {
+ return $this->dimension;
+ }
+
+ public function getOrder()
+ {
+ return $this->order;
+ }
+
public function getModule()
{
return $this->module;
diff --git a/core/Translate.php b/core/Translate.php
index 33061e0aa6..c128fd672a 100644
--- a/core/Translate.php
+++ b/core/Translate.php
@@ -224,4 +224,18 @@ class Translate
setlocale(LC_ALL, $locale, $locale_variant);
setlocale(LC_CTYPE, '');
}
+
+ public static function findTranslationKeyForTranslation($translation)
+ {
+ if (empty($GLOBALS['Piwik_translations'])) {
+ return;
+ }
+
+ foreach ($GLOBALS['Piwik_translations'] as $key => $translations) {
+ $possibleKey = array_search($translation, $translations);
+ if (!empty($possibleKey)) {
+ return $key . '_' . $possibleKey;
+ }
+ }
+ }
}
diff --git a/plugins/CoreConsole/Commands/GenerateReport.php b/plugins/CoreConsole/Commands/GenerateReport.php
new file mode 100644
index 0000000000..aa34b25c51
--- /dev/null
+++ b/plugins/CoreConsole/Commands/GenerateReport.php
@@ -0,0 +1,280 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+
+namespace Piwik\Plugins\CoreConsole\Commands;
+
+use Piwik\Plugin\Report;
+use Piwik\Translate;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+/**
+ * TODO we should automatically create a method in the API (works currently only if there is no API.php yet)
+ * TODO automatically create or modify translation file for instance for report name
+ */
+class GenerateReport extends GeneratePluginBase
+{
+ protected function configure()
+ {
+ $this->setName('generate:report')
+ ->setDescription('Adds a new report to an existing plugin')
+ ->addOption('pluginname', null, InputOption::VALUE_REQUIRED, 'The name of an existing plugin which does not have a menu defined yet')
+ ->addOption('reportname', null, InputOption::VALUE_REQUIRED, 'The name of the report you want to create')
+ ->addOption('category', null, InputOption::VALUE_REQUIRED, 'The name of the category the report belongs to')
+ ->addOption('dimension', null, InputOption::VALUE_OPTIONAL, 'The name of the dimension in case your report has a dimension')
+ ->addOption('documentation', null, InputOption::VALUE_REQUIRED, 'A documentation that explains what your report is about');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $pluginName = $this->getPluginName($input, $output);
+ $reportName = $this->getReportName($input, $output);
+ $category = $this->getCategory($input, $output, $pluginName);
+ $documentation = $this->getDocumentation($input, $output);
+ list($dimension, $dimensionClass) = $this->getDimension($input, $output);
+
+ $order = $this->getOrder($category);
+ $apiName = $this->getApiName($reportName);
+
+ $exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExamplePlugin';
+ $replace = array('ExamplePlugin' => $pluginName,
+ 'GetExampleReport' => ucfirst($apiName),
+ 'getExampleReport' => lcfirst($apiName),
+ 'getApiReport' => lcfirst($apiName),
+ 'ExampleCategory' => $category,
+ 'ExampleReportName' => $reportName,
+ 'ExampleReportDocumentation' => $documentation,
+ '999' => $order,
+ 'new ExitPageUrl()' => $dimension,
+ 'use Piwik\Plugins\Actions\Columns\ExitPageUrl;' => $dimensionClass
+ );
+ $whitelistFiles = array('/Reports', '/Reports/Base.php', '/Reports/GetExampleReport.php', '/API.php');
+
+ $this->copyTemplateToPlugin($exampleFolder, $pluginName, $replace, $whitelistFiles);
+
+ $this->writeSuccessMessage($output, array(
+ sprintf('Reports/%s.php for %s generated.', ucfirst($apiName), $pluginName),
+ 'You should now implement the method called "' . lcfirst($apiName) . '" in API.php',
+ // 'Read more about this here: link to developer guide',
+ 'Enjoy!'
+ ));
+ }
+
+ private function getOrder($category)
+ {
+ $order = 1;
+
+ foreach (Report::getAllReports() as $report) {
+ if ($report->getCategory() === $category) {
+ if ($report->getOrder() > $order) {
+ $order = $report->getOrder() + 1;
+ }
+ }
+ }
+
+ return $order;
+ }
+
+ private function getApiName($reportName)
+ {
+ $reportName = trim($reportName);
+ $reportName = str_replace(' ', '', $reportName);
+ $reportName = preg_replace("/[^A-Za-z0-9]/", '', $reportName);
+
+ $apiName = 'get' . ucfirst($reportName);
+
+ return lcfirst($apiName);
+ }
+
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @return array
+ * @throws \RunTimeException
+ */
+ protected function getReportName(InputInterface $input, OutputInterface $output)
+ {
+ $validate = function ($reportName) {
+ if (empty($reportName)) {
+ throw new \InvalidArgumentException('Please enter the name of your report');
+ }
+
+ if (preg_match("/[^A-Za-z0-9 ]/", $reportName)) {
+ throw new \InvalidArgumentException('Only alpha numerical characters and whitespaces are allowed');
+ }
+
+ return $reportName;
+ };
+
+ $reportName = $input->getOption('reportname');
+
+ if (empty($reportName)) {
+ $dialog = $this->getHelperSet()->get('dialog');
+ $reportName = $dialog->askAndValidate($output, 'Enter the name of your report, for instance "Browser Families": ', $validate);
+ } else {
+ $validate($reportName);
+ }
+
+ $reportName = ucfirst($reportName);
+
+ return $reportName;
+ }
+
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @return array
+ * @throws \RunTimeException
+ */
+ protected function getDocumentation(InputInterface $input, OutputInterface $output)
+ {
+ $validate = function ($documentation) {
+ if (empty($documentation)) {
+ return '';
+ }
+
+ return $documentation;
+ };
+
+ $documentation = $input->getOption('documentation');
+
+ if (empty($documentation)) {
+ $dialog = $this->getHelperSet()->get('dialog');
+ $documentation = $dialog->askAndValidate($output, 'Enter a documentation that describes the data of your report (you can leave it empty and define it later): ', $validate);
+ } else {
+ $validate($documentation);
+ }
+
+ $documentation = ucfirst($documentation);
+
+ return $documentation;
+ }
+
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @param string $pluginName
+ * @return array
+ * @throws \RunTimeException
+ */
+ protected function getCategory(InputInterface $input, OutputInterface $output, $pluginName)
+ {
+ $path = $this->getPluginPath($pluginName) . '/Reports/Base.php';
+ if (file_exists($path)) {
+ // category is already defined in base.php
+ return '';
+ }
+
+ $validate = function ($category) {
+ if (empty($category)) {
+ throw new \InvalidArgumentException('Please enter the name of the category your report belongs to');
+ }
+
+ return $category;
+ };
+
+ $category = $input->getOption('category');
+
+ $categories = array();
+ foreach (Report::getAllReports() as $report) {
+ if ($report->getCategory()) {
+ $categories[] = $report->getCategory();
+ }
+ }
+ $categories = array_values(array_unique($categories));
+
+ if (empty($category)) {
+ $dialog = $this->getHelperSet()->get('dialog');
+ $category = $dialog->askAndValidate($output, 'Enter the report category, for instance "Visitor" (you can reuse any existing category or define a new one): ', $validate, false, null, $categories);
+ } else {
+ $validate($category);
+ }
+
+ $translationKey = Translate::findTranslationKeyForTranslation($category);
+ if (!empty($translationKey)) {
+ return $translationKey;
+ }
+
+ $category = ucfirst($category);
+
+ return $category;
+ }
+
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @return array
+ * @throws \RunTimeException
+ */
+ protected function getDimension(InputInterface $input, OutputInterface $output)
+ {
+ $dimensions = array();
+ $dimensionNames = array();
+
+ foreach (Report::getAllReports() as $report) {
+ $dimension = $report->getDimension();
+ if (is_object($dimension)) {
+ $name = $dimension->getName();
+ if (!empty($name)) {
+ $dimensions[$name] = get_class($dimension);
+ $dimensionNames[] = $name;
+ }
+ }
+ }
+
+ $dimensionNames = array_values(array_unique($dimensionNames));
+
+ $validate = function ($dimension) use ($dimensions) {
+ if (empty($dimension)) {
+ return '';
+ }
+
+ if (!empty($dimension) && !array_key_exists($dimension, $dimensions)) {
+ throw new \InvalidArgumentException('Leave dimension either empty or use an existing one. You can also create a new dimension by calling .console generate:dimension before generating this report.');
+ }
+
+ return $dimension;
+ };
+
+ $actualDimension = $input->getOption('dimension');
+
+ if (null === $actualDimension) {
+ $dialog = $this->getHelperSet()->get('dialog');
+ $actualDimension = $dialog->askAndValidate($output, 'Enter the report dimension, for instance "Browser" (you can leave it either empty or use an existing one): ', $validate, false, null, $dimensionNames);
+ } else {
+ $validate($actualDimension);
+ }
+
+ if (empty($actualDimension)) {
+ return array('null', '');
+ }
+
+ $className = $dimensions[$actualDimension];
+ $parts = explode('\\', $className);
+ $name = end($parts);
+
+ return array('new ' . $name . '()', 'use ' . $className . ';');
+ }
+
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @return array
+ * @throws \RunTimeException
+ */
+ protected function getPluginName(InputInterface $input, OutputInterface $output)
+ {
+ $pluginNames = $this->getPluginNames();
+ $invalidName = 'You have to enter a name of an existing plugin.';
+
+ return $this->askPluginNameAndValidate($input, $output, $pluginNames, $invalidName);
+ }
+
+}
diff --git a/plugins/ExamplePlugin/API.php b/plugins/ExamplePlugin/API.php
index ffa887761f..b4274cf94d 100644
--- a/plugins/ExamplePlugin/API.php
+++ b/plugins/ExamplePlugin/API.php
@@ -8,6 +8,9 @@
*/
namespace Piwik\Plugins\ExamplePlugin;
+use Piwik\DataTable;
+use Piwik\DataTable\Row;
+
/**
* API for plugin ExamplePlugin
*
@@ -33,4 +36,17 @@ class API extends \Piwik\Plugin\API
return 24;
}
+
+ /**
+ * Another example method that returns a data table.
+ * @return DataTable
+ */
+ public function getApiReport()
+ {
+ $table = new DataTable();
+
+ $table->addRowFromArray(array(Row::COLUMNS => array('nb_visits' => 5)));
+
+ return $table;
+ }
}
diff --git a/plugins/ExamplePlugin/Reports/Base.php b/plugins/ExamplePlugin/Reports/Base.php
new file mode 100644
index 0000000000..2375b07844
--- /dev/null
+++ b/plugins/ExamplePlugin/Reports/Base.php
@@ -0,0 +1,19 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\ExamplePlugin\Reports;
+
+use Piwik\Plugin\Report;
+
+class Base extends Report
+{
+ protected function init()
+ {
+ $this->category = 'ExampleCategory';
+ }
+}
diff --git a/plugins/ExamplePlugin/Reports/GetExampleReport.php b/plugins/ExamplePlugin/Reports/GetExampleReport.php
new file mode 100644
index 0000000000..9fd00bd8c1
--- /dev/null
+++ b/plugins/ExamplePlugin/Reports/GetExampleReport.php
@@ -0,0 +1,111 @@
+<?php
+/**
+ * Piwik - free/libre analytics platform
+ *
+ * @link http://piwik.org
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
+ *
+ */
+namespace Piwik\Plugins\ExamplePlugin\Reports;
+
+use Piwik\Piwik;
+use Piwik\Plugin\Report;
+use Piwik\Plugin\ViewDataTable;
+use Piwik\Plugins\Actions\Columns\ExitPageUrl;
+use Piwik\View;
+
+class GetExampleReport extends Base
+{
+ protected function init()
+ {
+ parent::init();
+
+ $this->name = Piwik::translate('ExampleReportName');
+ $this->dimension = new ExitPageUrl();
+ $this->documentation = Piwik::translate('ExampleReportDocumentation');
+
+ // This defines in which order your report appears in the mobile app, in the menu and in the list of widgets
+ $this->order = 999;
+
+ // By default standard metrics are defined but you can customize them by defining an array of metric names
+ // $this->metrics = array('nb_visits', 'nb_hits');
+
+ // Uncomment the next line if your report does not contain any processed metrics, otherwise default
+ // processed metrics will be assigned
+ // $this->processedMetrics = array();
+
+ // Uncomment the next line if your report defines goal metrics
+ // $this->hasGoalMetrics = true;
+
+ // Uncomment the next line if your report should be able to load subtables. You can define any action here
+ // $this->actionToLoadSubTables = $this->action;
+
+ // Uncomment the next line if your report always returns a constant count of rows, for instance always
+ // 24 rows for 1-24hours
+ // $this->constantRowsCount = true;
+
+ // If a menu title is specified, the report will be displayed in the menu
+ // $this->menuTitle = 'ExampleReportName';
+
+ // If a widget title is specified, the report will be displayed in the list of widgets and the report can be
+ // exported as a widget
+ // $this->widgetTitle = 'ExampleReportName';
+ }
+
+ /**
+ * Here you can configure how your report should be displayed. For instance whether your report supports a search
+ * etc. You can also change the default request config. For instance change how many rows are displayed by default.
+ *
+ * @param ViewDataTable $view
+ */
+ public function configureView(ViewDataTable $view)
+ {
+ if (!empty($this->dimension)) {
+ $view->config->addTranslations(array('label' => $this->dimension->getName()));
+ }
+
+ // $view->config->show_search = false;
+ // $view->requestConfig->filter_sort_column = 'nb_visits';
+ // $view->requestConfig->filter_limit = 10';
+
+ $view->config->columns_to_display = array_merge(array('label'), $this->metrics);
+ }
+
+ /**
+ * Here you can define related reports that will be shown below the reports. Just return an array of related
+ * report instances if there are any.
+ *
+ * @return \Piwik\Plugin\Report[]
+ */
+ public function getRelatedReports()
+ {
+ return array(); // eg return array(new XyzReport());
+ }
+
+ /**
+ * A report is usually completely automatically rendered for you but you can render the report completely
+ * customized if you wish. Just overwrite the method and make sure to return a string containing the content of the
+ * report. Don't forget to create the defined twig template within the templates folder of your plugin in order to
+ * make it work. Usually you should NOT have to overwrite this render method.
+ *
+ * @return string
+ public function render()
+ {
+ $view = new View('@ExamplePlugin/getExampleReport');
+ $view->myData = array();
+
+ return $view->render();
+ }
+ */
+
+ /**
+ * By default your report is available to all users having at least view access. If you do not want this, you can
+ * limit the audience by overwriting this method.
+ *
+ * @return bool
+ public function isEnabled()
+ {
+ return Piwik::hasUserSuperUserAccess()
+ }
+ */
+}
diff --git a/plugins/Feedback/API.php b/plugins/Feedback/API.php
index bcaeb77650..ce6acdce20 100644
--- a/plugins/Feedback/API.php
+++ b/plugins/Feedback/API.php
@@ -78,20 +78,6 @@ class API extends \Piwik\Plugin\API
@$mail->send();
}
- private function findTranslationKeyForFeatureName($featureName)
- {
- if (empty($GLOBALS['Piwik_translations'])) {
- return;
- }
-
- foreach ($GLOBALS['Piwik_translations'] as $key => $translations) {
- $possibleKey = array_search($featureName, $translations);
- if (!empty($possibleKey)) {
- return $key . '_' . $possibleKey;
- }
- }
- }
-
private function getEnglishTranslationForFeatureName($featureName)
{
$loadedLanguage = Translate::getLanguageLoaded();
@@ -100,7 +86,7 @@ class API extends \Piwik\Plugin\API
return $featureName;
}
- $translationKeyForFeature = $this->findTranslationKeyForFeatureName($featureName);
+ $translationKeyForFeature = Translate::findTranslationKeyForTranslation($featureName);
if (!empty($translationKeyForFeature)) {
Translate::reloadLanguage('en');