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/Development.php138
-rw-r--r--core/Updater.php2
-rw-r--r--plugins/CoreConsole/Commands/GenerateDimension.php57
-rw-r--r--plugins/CoreConsole/Commands/GeneratePluginBase.php169
-rw-r--r--plugins/CoreConsole/Commands/GenerateReport.php17
-rw-r--r--plugins/CoreConsole/Commands/GenerateUpdate.php118
-rw-r--r--plugins/CoreConsole/Commands/GenerateVisualizationPlugin.php6
-rw-r--r--plugins/VisitTime/Reports/GetVisitInformationPerServerTime.php1
8 files changed, 442 insertions, 66 deletions
diff --git a/core/Development.php b/core/Development.php
index c0d34f11e9..60d3dcd81c 100644
--- a/core/Development.php
+++ b/core/Development.php
@@ -12,17 +12,21 @@ namespace Piwik;
use \Exception;
/**
- * Development related checks and tools
+ * Development related checks and tools. You can enable/disable development using `./console development:enable` and
+ * `./console development:disable`. The intention of the development mode and this class is to support the developer
+ * as much as possible by doing some additional checks if the development mode is enabled. For instance if a developer
+ * has to register any class/method we can make sure whether they actually exist and if not display a useful error
+ * message. This helps the user to find for instance simple typos and makes sure it will actually work even if he
+ * forgets to test it.
*/
class Development
{
private static $isEnabled = null;
/**
- * Returns `true` if segmentation is allowed for this user, `false` if otherwise.
+ * Returns `true` if development mode is enabled and `false` otherwise.
*
* @return bool
- * @api
*/
public static function isEnabled()
{
@@ -33,50 +37,110 @@ class Development
return self::$isEnabled;
}
- public static function methodExists($classOrInstance, $method)
+ /**
+ * Verifies whether a className of object implements the given method. It does not check whether the given method
+ * is actually callable (public).
+ *
+ * @param string|object $classOrObject
+ * @param string $method
+ *
+ * @return bool true if the method exists, false otherwise.
+ */
+ public static function methodExists($classOrObject, $method)
{
- if (is_string($classOrInstance)) {
- return class_exists($classOrInstance) && method_exists($classOrInstance, $method);
+ if (is_string($classOrObject)) {
+ return class_exists($classOrObject) && method_exists($classOrObject, $method);
}
- return method_exists($classOrInstance, $method);
+ return method_exists($classOrObject, $method);
}
- public static function formatMethodCall($classOrInstance, $method)
+ /**
+ * Formats a method call depending on the given class/object and method name. It does not perform any checks whether
+ * does actually exists.
+ *
+ * @param string|object $classOrObject
+ * @param string $method
+ *
+ * @return string Formatted method call. Example: "MyNamespace\MyClassname::methodName()"
+ */
+ public static function formatMethodCall($classOrObject, $method)
{
- if (is_object($classOrInstance)) {
- $classOrInstance = get_class($classOrInstance);
+ if (is_object($classOrObject)) {
+ $classOrObject = get_class($classOrObject);
}
- return $classOrInstance . '::' . $method . '()';
+ return $classOrObject . '::' . $method . '()';
}
- public static function checkMethodIsCallable($classOrInstance, $method, $prefixMessageIfError)
+ /**
+ * Checks whether the given method is actually callable on the given class/object if the development mode is
+ * enabled. En error will be triggered if the method does not exist or is not callable (public) containing a useful
+ * error message for the developer.
+ *
+ * @param string|object $classOrObject
+ * @param string $method
+ * @param string $prefixMessageIfError You can prepend any string to the error message in case the method is not
+ * callable.
+ */
+ public static function checkMethodIsCallable($classOrObject, $method, $prefixMessageIfError)
{
if (!self::isEnabled()) {
return;
}
- if (!self::methodExists($classOrInstance, $method)) {
- self::error($prefixMessageIfError . ' "' . self::formatMethodCall($classOrInstance, $method) . '" does not exist. Please make sure to define such a method.');
+ self::checkMethodExists($classOrObject, $method, $prefixMessageIfError);
+
+ if (!self::isCallableMethod($classOrObject, $method)) {
+ self::error($prefixMessageIfError . ' "' . self::formatMethodCall($classOrObject, $method) . '" is not callable. Please make sure to method is public');
}
+ }
- if (!self::isCallableMethod($classOrInstance, $method)) {
- self::error($prefixMessageIfError . ' "' . self::formatMethodCall($classOrInstance, $method) . '" is not callable. Please make sure to method is public');
+ /**
+ * Checks whether the given method is actually callable on the given class/object if the development mode is
+ * enabled. En error will be triggered if the method does not exist or is not callable (public) containing a useful
+ * error message for the developer.
+ *
+ * @param string|object $classOrObject
+ * @param string $method
+ * @param string $prefixMessageIfError You can prepend any string to the error message in case the method is not
+ * callable.
+ */
+ public static function checkMethodExists($classOrObject, $method, $prefixMessageIfError)
+ {
+ if (!self::isEnabled()) {
+ return;
+ }
+ if (!self::methodExists($classOrObject, $method)) {
+ self::error($prefixMessageIfError . ' "' . self::formatMethodCall($classOrObject, $method) . '" does not exist. Please make sure to define such a method.');
}
}
- public static function isCallableMethod($classOrInstance, $method)
+ /**
+ * Verify whether the given method actually exists and is callable (public).
+ *
+ * @param string|object $classOrObject
+ * @param string $method
+ * @return bool
+ */
+ public static function isCallableMethod($classOrObject, $method)
{
- if (!self::methodExists($classOrInstance, $method)) {
+ if (!self::methodExists($classOrObject, $method)) {
return false;
}
- $reflection = new \ReflectionMethod($classOrInstance, $method);
+ $reflection = new \ReflectionMethod($classOrObject, $method);
return $reflection->isPublic();
}
+ /**
+ * Triggers an error if the development mode is enabled. Depending on the current environment / mode it will either
+ * log the given message or throw an exception to make sure it will be displayed in the Piwik UI.
+ *
+ * @param string $message
+ * @throws Exception
+ */
public static function error($message)
{
if (!self::isEnabled()) {
@@ -91,6 +155,42 @@ class Development
} else {
throw new Exception($message);
}
+ }
+
+ public static function getMethodSourceCode($className, $methodName)
+ {
+ $method = new \ReflectionMethod($className, $methodName);
+
+ $file = new \SplFileObject($method->getFileName());
+ $offset = $method->getStartLine() - 1;
+ $count = $method->getEndLine() - $method->getStartLine() + 1;
+
+ $fileIterator = new \LimitIterator($file, $offset, $count);
+
+ $methodCode = "\n " . $method->getDocComment() . "\n";
+ foreach($fileIterator as $line) {
+ $methodCode .= $line;
+ }
+ $methodCode .= "\n";
+
+ return $methodCode;
+ }
+
+ public static function getUseStatements($className)
+ {
+ $class = new \ReflectionClass($className);
+
+ $file = new \SplFileObject($class->getFileName());
+
+ $fileIterator = new \LimitIterator($file, 0, $class->getStartLine());
+
+ $uses = array();
+ foreach($fileIterator as $line) {
+ if (preg_match('/(\s*)use (.+)/', $line, $match)) {
+ $uses[] = trim($match[2]);
+ }
+ }
+ return $uses;
}
}
diff --git a/core/Updater.php b/core/Updater.php
index e10c6bf33c..6cd6bf757f 100644
--- a/core/Updater.php
+++ b/core/Updater.php
@@ -170,7 +170,7 @@ class Updater
return $queries;
}
- private function getUpdateClassName($componentName, $fileVersion)
+ public function getUpdateClassName($componentName, $fileVersion)
{
$suffix = strtolower(str_replace(array('-', '.'), '_', $fileVersion));
$className = 'Updates_' . $suffix;
diff --git a/plugins/CoreConsole/Commands/GenerateDimension.php b/plugins/CoreConsole/Commands/GenerateDimension.php
index ad752b0a78..73c2984d1b 100644
--- a/plugins/CoreConsole/Commands/GenerateDimension.php
+++ b/plugins/CoreConsole/Commands/GenerateDimension.php
@@ -17,9 +17,6 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
-/**
- * TODO automatically create or modify translation file for instance for dimension name
- */
class GenerateDimension extends GeneratePluginBase
{
protected function configure()
@@ -33,27 +30,40 @@ class GenerateDimension extends GeneratePluginBase
->addOption('columntype', null, InputOption::VALUE_REQUIRED, 'The MySQL type for your dimension, for instance "VARCHAR(255) NOT NULL".');
}
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @throws \InvalidArgumentException
+ */
protected function execute(InputInterface $input, OutputInterface $output)
{
$pluginName = $this->getPluginName($input, $output);
$type = $this->getDimensionType($input, $output);
$dimensionName = $this->getDimensionName($input, $output);
- $columnName = $this->getColumnName($input, $output, $type);
- $columType = $this->getColumnType($input, $output);
-
- $dimensionClassName = $this->getDimensionClassName($dimensionName);
-
- $exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExamplePlugin';
- $replace = array('example_action_dimension' => strtolower($columnName),
- 'example_visit_dimension' => strtolower($columnName),
- 'example_conversion_dimension' => strtolower($columnName),
- 'INTEGER(11) DEFAULT 0 NOT NULL' => strtoupper($columType),
- 'VARCHAR(255) DEFAULT NULL' => strtoupper($columType),
- 'ExampleVisitDimension' => $dimensionClassName,
- 'ExampleActionDimension' => $dimensionClassName,
- 'ExampleConversionDimension' => $dimensionClassName,
- 'ExamplePlugin_DimensionName' => ucfirst($dimensionName),
- 'ExamplePlugin' => $pluginName,
+
+ if ('non-tracking-dimension' === $type) {
+ $columnName = '';
+ $columType = '';
+ } else {
+ $columnName = $this->getColumnName($input, $output, $type);
+ $columType = $this->getColumnType($input, $output);
+ }
+
+ $dimensionClassName = $this->getDimensionClassName($dimensionName);
+ $translatedDimensionName = $this->makeTranslationIfPossible($pluginName, ucfirst($dimensionName));
+
+ $exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExamplePlugin';
+ $replace = array('example_action_dimension' => strtolower($columnName),
+ 'example_visit_dimension' => strtolower($columnName),
+ 'example_conversion_dimension' => strtolower($columnName),
+ 'INTEGER(11) DEFAULT 0 NOT NULL' => strtoupper($columType),
+ 'VARCHAR(255) DEFAULT NULL' => strtoupper($columType),
+ 'ExampleDimension' => $dimensionClassName,
+ 'ExampleVisitDimension' => $dimensionClassName,
+ 'ExampleActionDimension' => $dimensionClassName,
+ 'ExampleConversionDimension' => $dimensionClassName,
+ 'ExamplePlugin_DimensionName' => $translatedDimensionName,
+ 'ExamplePlugin' => $pluginName,
);
$whitelistFiles = array('/Columns');
@@ -64,6 +74,8 @@ class GenerateDimension extends GeneratePluginBase
$whitelistFiles[] = '/Columns/ExampleActionDimension.php';
} elseif ('conversion' == $type) {
$whitelistFiles[] = '/Columns/ExampleConversionDimension.php';
+ } elseif ('non-tracking-dimension' == $type) {
+ $whitelistFiles[] = '/Columns/ExampleDimension.php';
} else {
throw new \InvalidArgumentException('This dimension type is not available');
}
@@ -125,6 +137,7 @@ class GenerateDimension extends GeneratePluginBase
/**
* @param InputInterface $input
* @param OutputInterface $output
+ * @param string $type
* @return array
* @throws \RunTimeException
*/
@@ -206,11 +219,11 @@ class GenerateDimension extends GeneratePluginBase
*/
protected function getDimensionType(InputInterface $input, OutputInterface $output)
{
- $acceptedValues = array('visit', 'action', 'conversion');
+ $acceptedValues = array('visit', 'action', 'conversion', 'non-tracking-dimension');
$validate = function ($type) use ($acceptedValues) {
if (empty($type) || !in_array($type, $acceptedValues)) {
- throw new \InvalidArgumentException('Please enter a valid dimension type (' . implode(', ', $acceptedValues) . '): ');
+ throw new \InvalidArgumentException('Please enter a valid dimension type (' . implode(', ', $acceptedValues) . '). Choose "non-tracking-dimension" if you only need a blank dimension having a name: ');
}
return $type;
@@ -220,7 +233,7 @@ class GenerateDimension extends GeneratePluginBase
if (empty($type)) {
$dialog = $this->getHelperSet()->get('dialog');
- $type = $dialog->askAndValidate($output, 'Please choose the type of dimension you want to create (' . implode(', ', $acceptedValues) . '): ', $validate, false, null, $acceptedValues);
+ $type = $dialog->askAndValidate($output, 'Please choose the type of dimension you want to create (' . implode(', ', $acceptedValues) . '). Choose "non-tracking-dimension" if you only need a blank dimension having a name: ', $validate, false, null, $acceptedValues);
} else {
$validate($type);
}
diff --git a/plugins/CoreConsole/Commands/GeneratePluginBase.php b/plugins/CoreConsole/Commands/GeneratePluginBase.php
index 8c17304aaa..cd90321fec 100644
--- a/plugins/CoreConsole/Commands/GeneratePluginBase.php
+++ b/plugins/CoreConsole/Commands/GeneratePluginBase.php
@@ -10,13 +10,12 @@
namespace Piwik\Plugins\CoreConsole\Commands;
+use Piwik\Development;
use Piwik\Filesystem;
use Piwik\Plugin\ConsoleCommand;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
-/**
- */
abstract class GeneratePluginBase extends ConsoleCommand
{
public function getPluginPath($pluginName)
@@ -24,18 +23,26 @@ abstract class GeneratePluginBase extends ConsoleCommand
return PIWIK_INCLUDE_PATH . '/plugins/' . ucfirst($pluginName);
}
- private function createFolderWithinPluginIfNotExists($pluginName, $folder)
+ private function createFolderWithinPluginIfNotExists($pluginNameOrCore, $folder)
{
- $pluginPath = $this->getPluginPath($pluginName);
+ if ($pluginNameOrCore === 'core') {
+ $pluginPath = $this->getPathToCore();
+ } else {
+ $pluginPath = $this->getPluginPath($pluginNameOrCore);
+ }
- if (!file_exists($pluginName . $folder)) {
+ if (!file_exists($pluginPath . $folder)) {
Filesystem::mkdir($pluginPath . $folder);
}
}
- protected function createFileWithinPluginIfNotExists($pluginName, $fileName, $content)
+ protected function createFileWithinPluginIfNotExists($pluginNameOrCore, $fileName, $content)
{
- $pluginPath = $this->getPluginPath($pluginName);
+ if ($pluginNameOrCore === 'core') {
+ $pluginPath = $this->getPathToCore();
+ } else {
+ $pluginPath = $this->getPluginPath($pluginNameOrCore);
+ }
if (!file_exists($pluginPath . $fileName)) {
file_put_contents($pluginPath . $fileName, $content);
@@ -43,6 +50,131 @@ abstract class GeneratePluginBase extends ConsoleCommand
}
/**
+ * Creates a lang/en.json within the plugin in case it does not exist yet and adds a translation for the given
+ * text.
+ *
+ * @param $pluginName
+ * @param $translatedText
+ * @return string Either the generated translation key or the original text if a different translation for this
+ * generated translation key already exists.
+ */
+ protected function makeTranslationIfPossible($pluginName, $translatedText)
+ {
+ $defaultLang = array($pluginName => array());
+
+ $this->createFolderWithinPluginIfNotExists($pluginName, '/lang');
+ $this->createFileWithinPluginIfNotExists($pluginName, '/lang/en.json', $this->toJson($defaultLang));
+
+ $langJsonPath = $this->getPluginPath($pluginName) . '/lang/en.json';
+ $translations = file_get_contents($langJsonPath);
+ $translations = json_decode($translations, true);
+
+ if (empty($translations[$pluginName])) {
+ $translations[$pluginName] = array();
+ }
+
+ $key = $this->buildTranslationKey($translatedText);
+
+ if (array_key_exists($key, $translations[$pluginName])) {
+ // we do not want to overwrite any existing translations
+ if ($translations[$pluginName][$key] === $translatedText) {
+ return $pluginName . '_' . $key;
+ }
+
+ return $translatedText;
+ }
+
+ $translations[$pluginName][$key] = $this->removeNonJsonCompatibleCharacters($translatedText);
+
+ file_put_contents($langJsonPath, $this->toJson($translations));
+
+ return $pluginName . '_' . $key;
+ }
+
+ private function toJson($value)
+ {
+ if (defined('JSON_PRETTY_PRINT')) {
+
+ return json_encode($value, JSON_PRETTY_PRINT);
+ }
+
+ return json_encode($value);
+ }
+
+ private function buildTranslationKey($translatedText)
+ {
+ $translatedText = preg_replace('/(\s+)/', '', $translatedText);
+ $translatedText = preg_replace("/[^A-Za-z0-9]/", '', $translatedText);
+ $translatedText = trim($translatedText);
+
+ return $this->removeNonJsonCompatibleCharacters($translatedText);
+ }
+
+ private function removeNonJsonCompatibleCharacters($text)
+ {
+ return preg_replace('/[^(\x00-\x7F)]*/', '', $text);
+ }
+
+ /**
+ * Copies the given method and all needed use statements into an existing class. The target class name will be
+ * built based on the given $replace argument.
+ * @param string $sourceClassName
+ * @param string $methodName
+ * @param array $replace
+ */
+ protected function copyTemplateMethodToExisitingClass($sourceClassName, $methodName, $replace)
+ {
+ $targetClassName = $this->replaceContent($replace, $sourceClassName);
+
+ if (Development::methodExists($targetClassName, $methodName)) {
+ // we do not want to add the same method twice
+ return;
+ }
+
+ Development::checkMethodExists($sourceClassName, $methodName, 'Cannot copy template method: ');
+
+ $targetClass = new \ReflectionClass($targetClassName);
+ $file = new \SplFileObject($targetClass->getFileName());
+
+ $methodCode = Development::getMethodSourceCode($sourceClassName, $methodName);
+ $methodCode = $this->replaceContent($replace, $methodCode);
+ $methodLine = $targetClass->getEndLine() - 1;
+
+ $sourceUses = Development::getUseStatements($sourceClassName);
+ $targetUses = Development::getUseStatements($targetClassName);
+ $usesToAdd = array_diff($sourceUses, $targetUses);
+ if (empty($usesToAdd)) {
+ $useCode = '';
+ } else {
+ $useCode = "\nuse " . implode("\nuse ", $usesToAdd) . "\n";
+ }
+
+ // search for namespace line before the class starts
+ $useLine = 0;
+ foreach (new \LimitIterator($file, 0, $targetClass->getStartLine()) as $index => $line) {
+ if (0 === strpos(trim($line), 'namespace ')) {
+ $useLine = $index + 1;
+ break;
+ }
+ }
+
+ $newClassCode = '';
+ foreach(new \LimitIterator($file) as $index => $line) {
+ if ($index == $methodLine) {
+ $newClassCode .= $methodCode;
+ }
+
+ if (0 !== $useLine && $index == $useLine) {
+ $newClassCode .= $useCode;
+ }
+
+ $newClassCode .= $line;
+ }
+
+ file_put_contents($targetClass->getFileName(), $newClassCode);
+ }
+
+ /**
* @param string $templateFolder full path like /home/...
* @param string $pluginName
* @param array $replace array(key => value) $key will be replaced by $value in all templates
@@ -70,13 +202,9 @@ abstract class GeneratePluginBase extends ConsoleCommand
$this->createFolderWithinPluginIfNotExists($pluginName, $fileNamePlugin);
} else {
$template = file_get_contents($file);
- foreach ($replace as $key => $value) {
- $template = str_replace($key, $value, $template);
- }
+ $template = $this->replaceContent($replace, $template);
- foreach ($replace as $key => $value) {
- $fileNamePlugin = str_replace($key, $value, $fileNamePlugin);
- }
+ $fileNamePlugin = $this->replaceContent($replace, $fileNamePlugin);
$this->createFileWithinPluginIfNotExists($pluginName, $fileNamePlugin, $template);
}
@@ -140,4 +268,19 @@ abstract class GeneratePluginBase extends ConsoleCommand
return $pluginName;
}
+ private function getPathToCore()
+ {
+ $path = PIWIK_INCLUDE_PATH . '/core';
+ return $path;
+ }
+
+ private function replaceContent($replace, $contentToReplace)
+ {
+ foreach ((array) $replace as $key => $value) {
+ $contentToReplace = str_replace($key, $value, $contentToReplace);
+ }
+
+ return $contentToReplace;
+ }
+
}
diff --git a/plugins/CoreConsole/Commands/GenerateReport.php b/plugins/CoreConsole/Commands/GenerateReport.php
index 7288fb6a16..d1e5cbbcf9 100644
--- a/plugins/CoreConsole/Commands/GenerateReport.php
+++ b/plugins/CoreConsole/Commands/GenerateReport.php
@@ -15,10 +15,6 @@ 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()
@@ -49,13 +45,20 @@ class GenerateReport extends GeneratePluginBase
'getExampleReport' => lcfirst($apiName),
'getApiReport' => lcfirst($apiName),
'ExampleCategory' => $category,
- 'ExampleReportName' => $reportName,
+ 'ExampleReportName' => $this->makeTranslationIfPossible($pluginName, $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');
+
+ $whitelistFiles = array('/Reports', '/Reports/Base.php', '/Reports/GetExampleReport.php');
+
+ if (file_exists($this->getPluginPath($pluginName) . '/API.php')) {
+ $this->copyTemplateMethodToExisitingClass('Piwik\Plugins\ExamplePlugin\API', 'getExampleReport', $replace);
+ } else {
+ $whitelistFiles[] = '/API.php';
+ }
$this->copyTemplateToPlugin($exampleFolder, $pluginName, $replace, $whitelistFiles);
@@ -224,7 +227,7 @@ class GenerateReport extends GeneratePluginBase
$name = $dimension->getName();
if (!empty($name)) {
$dimensions[$name] = get_class($dimension);
- $dimensionNames[] = $name;
+ $dimensionNames[] = $name;
}
}
}
diff --git a/plugins/CoreConsole/Commands/GenerateUpdate.php b/plugins/CoreConsole/Commands/GenerateUpdate.php
new file mode 100644
index 0000000000..745918666a
--- /dev/null
+++ b/plugins/CoreConsole/Commands/GenerateUpdate.php
@@ -0,0 +1,118 @@
+<?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;
+use Piwik\Updater;
+use Piwik\Version;
+use Symfony\Component\Console\Input\InputInterface;
+use Symfony\Component\Console\Input\InputOption;
+use Symfony\Component\Console\Output\OutputInterface;
+
+class GenerateUpdate extends GeneratePluginBase
+{
+ protected function configure()
+ {
+ $this->setName('generate:update')
+ ->setDescription('Adds a new update to an existing plugin or "core"')
+ ->addOption('component', null, InputOption::VALUE_REQUIRED, 'The name of an existing plugin or "core"');
+ }
+
+ protected function execute(InputInterface $input, OutputInterface $output)
+ {
+ $component = $this->getComponent($input, $output);
+
+ $version = $this->getVersion($component);
+ $namespace = $this->getNamespace($component);
+ $className = $this->getUpdateClassName($component, $version);
+
+ $exampleFolder = PIWIK_INCLUDE_PATH . '/plugins/ExamplePlugin';
+ $replace = array('Piwik\Plugins\ExamplePlugin' => $namespace,
+ 'ExamplePlugin' => $component,
+ 'Updates_0_0_2' => $className,
+ '0.0.2' => $version);
+ $whitelistFiles = array('/Updates', '/Updates/0.0.2.php');
+
+ $this->copyTemplateToPlugin($exampleFolder, $component, $replace, $whitelistFiles);
+
+ $this->writeSuccessMessage($output, array(
+ sprintf('Updates/%s.php for %s generated.', $version, $component),
+ 'You should have a look at the method update() or getSql() now.',
+ 'Enjoy!'
+ ));
+ }
+
+ private function getUpdateClassName($component, $version)
+ {
+ $updater = new Updater();
+ $className = $updater->getUpdateClassName($component, $version);
+ $parts = explode('\\', $className);
+
+ return end($parts);
+ }
+
+ private function getVersion($component)
+ {
+ if ($component === 'core') {
+ return Version::VERSION;
+ }
+
+ $pluginManager = Plugin\Manager::getInstance();
+
+ if ($pluginManager->isPluginLoaded($component)) {
+ $plugin = $pluginManager->getLoadedPlugin($component);
+ } else {
+ $plugin = new Plugin($component);
+ }
+
+ return $plugin->getVersion();
+ }
+
+ private function getNamespace($component)
+ {
+ $updater = new Updater();
+ $className = $updater->getUpdateClassName($component, 'xx');
+ $className = str_replace('Updates_xx', '', $className);
+ $className = trim($className, '\\');
+
+ return $className;
+ }
+
+ /**
+ * @param InputInterface $input
+ * @param OutputInterface $output
+ * @return array
+ * @throws \RunTimeException
+ */
+ private function getComponent(InputInterface $input, OutputInterface $output)
+ {
+ $components = $this->getPluginNames();
+ $components[] = 'core';
+
+ $validate = function ($component) use ($components) {
+ if (!in_array($component, $components)) {
+ throw new \InvalidArgumentException('You have to enter a name of an existing plugin or "core".');
+ }
+
+ return $component;
+ };
+
+ $component = $input->getOption('component');
+
+ if (empty($component)) {
+ $dialog = $this->getHelperSet()->get('dialog');
+ $component = $dialog->askAndValidate($output, 'Enter the name of your plugin or "core": ', $validate, false, null, $components);
+ } else {
+ $validate($component);
+ }
+
+ return $component;
+ }
+}
diff --git a/plugins/CoreConsole/Commands/GenerateVisualizationPlugin.php b/plugins/CoreConsole/Commands/GenerateVisualizationPlugin.php
index abb9d29cb5..b2f3d9ea11 100644
--- a/plugins/CoreConsole/Commands/GenerateVisualizationPlugin.php
+++ b/plugins/CoreConsole/Commands/GenerateVisualizationPlugin.php
@@ -43,7 +43,7 @@ class GenerateVisualizationPlugin extends GeneratePlugin
$replace = array(
'SimpleTable' => $visualizationName,
'simpleTable' => lcfirst($visualizationName),
- 'Simple Table' => $visualizationName,
+ 'Simple Table' => $this->makeTranslationIfPossible($pluginName, $visualizationName),
'ExampleVisualization' => $pluginName,
'ExampleVisualizationDescription' => $description
);
@@ -72,7 +72,7 @@ class GenerateVisualizationPlugin extends GeneratePlugin
}
if (!ctype_alnum($visualizationName)) {
- throw new \RunTimeException(sprintf('The visualization name %s is not valid', $visualizationName));
+ throw new \RunTimeException(sprintf('The visualization name %s is not valid (only AlNum allowed)', $visualizationName));
}
return $visualizationName;
@@ -82,7 +82,7 @@ class GenerateVisualizationPlugin extends GeneratePlugin
if (empty($visualizationName)) {
$dialog = $this->getHelperSet()->get('dialog');
- $visualizationName = $dialog->askAndValidate($output, 'Enter a visualization name: ', $validate);
+ $visualizationName = $dialog->askAndValidate($output, 'Enter a visualization name (only AlNum allowed): ', $validate);
} else {
$validate($visualizationName);
}
diff --git a/plugins/VisitTime/Reports/GetVisitInformationPerServerTime.php b/plugins/VisitTime/Reports/GetVisitInformationPerServerTime.php
index 9f9e9170f3..ea8e1b9f7e 100644
--- a/plugins/VisitTime/Reports/GetVisitInformationPerServerTime.php
+++ b/plugins/VisitTime/Reports/GetVisitInformationPerServerTime.php
@@ -34,7 +34,6 @@ class GetVisitInformationPerServerTime extends Base
$view->requestConfig->filter_limit = 24;
$view->requestConfig->request_parameters_to_modify['hideFutureHoursWhenToday'] = 1;
- $view->config->show_goals = true;
$view->config->addTranslation('label', $this->dimension->getName());
if ($view->isViewDataTableId(Graph::ID)) {